forked from AFPy/afpy.org
Drop unused jobs page.
Last job was posted on january 2022, 10 month ago.
This commit is contained in:
parent
1da49c227e
commit
754f4178d3
|
@ -47,18 +47,15 @@ def page_not_found(e):
|
|||
|
||||
from afpy.routes.home import home_bp
|
||||
from afpy.routes.posts import posts_bp, post_render
|
||||
from afpy.routes.jobs import jobs_bp, jobs_render
|
||||
from afpy.routes.rss import rss_bp
|
||||
|
||||
application.register_blueprint(home_bp)
|
||||
application.register_blueprint(posts_bp)
|
||||
application.register_blueprint(jobs_bp)
|
||||
application.register_blueprint(rss_bp)
|
||||
|
||||
|
||||
from afpy.models.AdminUser import AdminUser, AdminUser_Admin
|
||||
from afpy.models.NewsEntry import NewsEntry, NewsEntry_Admin
|
||||
from afpy.models.JobPost import JobPost, JobPost_Admin
|
||||
from afpy.models.Slug import Slug, SlugAdmin
|
||||
|
||||
|
||||
|
@ -66,7 +63,6 @@ from afpy.routes.admin import (
|
|||
AdminIndexView,
|
||||
NewAdminView,
|
||||
ChangePasswordView,
|
||||
JobsModerateView,
|
||||
NewsModerateView,
|
||||
CustomFileAdmin,
|
||||
)
|
||||
|
@ -81,10 +77,8 @@ admin = Admin(
|
|||
)
|
||||
|
||||
# Registers the views for each table
|
||||
admin.add_view(JobsModerateView(name="Moderate Jobs", endpoint="jobs_moderation", category="Moderate"))
|
||||
admin.add_view(NewsModerateView(name="Moderate News", endpoint="news_moderation", category="Moderate"))
|
||||
admin.add_view(NewsEntry_Admin(NewsEntry))
|
||||
admin.add_view(JobPost_Admin(JobPost))
|
||||
admin.add_view(SlugAdmin(Slug))
|
||||
admin.add_view(CustomFileAdmin(config.IMAGES_PATH, "/images/", name="Images Files"))
|
||||
admin.add_view(NewAdminView(name="New Admin", endpoint="register_admin", category="Admin"))
|
||||
|
@ -107,9 +101,6 @@ def get_slug_url(item):
|
|||
url_root = request.url_root
|
||||
slug = item.slug.where(Slug.canonical == True).first() # noqa
|
||||
if not slug:
|
||||
if isinstance(item, JobPost):
|
||||
return url_root[:-1] + "/emplois/" + str(item.id)
|
||||
else:
|
||||
return url_root[:-1] + "/actualites/" + str(item.id)
|
||||
else:
|
||||
return url_root[:-1] + slug.url
|
||||
|
@ -122,5 +113,3 @@ def slug_fallback(slug):
|
|||
abort(404)
|
||||
if slug.newsentry:
|
||||
return post_render(slug.newsentry.id)
|
||||
elif slug.jobpost:
|
||||
return jobs_render(slug.jobpost.id)
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
from flask_pagedown.fields import PageDownField
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import FileField
|
||||
from wtforms import StringField
|
||||
from wtforms import validators
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
|
||||
def validate_email_or_phone(form, field):
|
||||
if not form.email.data and not form.phone.data:
|
||||
raise validators.ValidationError("Must have phone or email")
|
||||
|
||||
|
||||
class JobPostForm(FlaskForm):
|
||||
title = StringField("Titre", validators=[DataRequired()])
|
||||
summary = StringField("Résumé (optionnel)")
|
||||
content = PageDownField("Contenu de l'offre", validators=[DataRequired()])
|
||||
company = StringField("Entreprise", validators=[DataRequired()])
|
||||
location = StringField("Addresse", validators=[DataRequired()])
|
||||
contact_info = StringField("Personne à contacter", validators=[DataRequired()])
|
||||
email = StringField("Email", validators=[validate_email_or_phone])
|
||||
phone = StringField("Téléphone", validators=[validate_email_or_phone])
|
||||
image = FileField("Image (optionnel)")
|
|
@ -1,111 +0,0 @@
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from flask_admin.contrib.peewee import ModelView
|
||||
from flask_login import current_user
|
||||
from peewee import CharField
|
||||
from peewee import DateTimeField
|
||||
from peewee import ForeignKeyField
|
||||
from peewee import TextField
|
||||
|
||||
from afpy.models import BaseModel
|
||||
from afpy.models.AdminUser import AdminUser
|
||||
|
||||
|
||||
class JobPost(BaseModel):
|
||||
title = TextField(null=False, help_text="Title of the job post", verbose_name="Title")
|
||||
summary = TextField(null=True, help_text="Summary of the job post", verbose_name="Summary")
|
||||
content = TextField(null=False, help_text="Content of the job post", verbose_name="Content")
|
||||
dt_submitted = DateTimeField(
|
||||
null=False,
|
||||
default=datetime.now,
|
||||
help_text="When was the job post submitted",
|
||||
verbose_name="Datetime Submitted",
|
||||
index=True,
|
||||
)
|
||||
dt_updated = DateTimeField(
|
||||
null=False, default=datetime.now, help_text="When was the job post updated", verbose_name="Datetime Updated"
|
||||
)
|
||||
dt_published = DateTimeField(
|
||||
null=True, help_text="When was the job post published", verbose_name="Datetime Published"
|
||||
)
|
||||
state = CharField(
|
||||
null=False,
|
||||
default="waiting",
|
||||
choices=[("waiting", "waiting"), ("published", "published"), ("rejected", "rejected")],
|
||||
help_text="Current state of the job post",
|
||||
verbose_name="State",
|
||||
)
|
||||
approved_by = ForeignKeyField(
|
||||
AdminUser,
|
||||
null=True,
|
||||
default=None,
|
||||
backref="adminuser",
|
||||
help_text="Who approved the job post",
|
||||
verbose_name="Approved by",
|
||||
)
|
||||
|
||||
company = CharField(null=False, help_text="Company that posted the job", verbose_name="Company")
|
||||
phone = CharField(null=True, help_text="Phone number to contact", verbose_name="Phone Number")
|
||||
location = CharField(null=False, help_text="Where is the job located", verbose_name="Job Location")
|
||||
email = CharField(null=True, help_text="Email to contact", verbose_name="Email Address")
|
||||
contact_info = CharField(null=False, help_text="Person to contact", verbose_name="Contact info")
|
||||
image_path = CharField(null=True, help_text="Image for the job post", verbose_name="Image Path in filesystem")
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
title: str,
|
||||
content: str,
|
||||
company: str,
|
||||
location: str,
|
||||
contact_info: str,
|
||||
email: Optional[str] = None,
|
||||
phone: Optional[str] = None,
|
||||
summary: Optional[str] = None,
|
||||
dt_submitted: Optional[datetime] = None,
|
||||
dt_updated: Optional[datetime] = None,
|
||||
dt_published: Optional[datetime] = None,
|
||||
state: str = "waiting",
|
||||
approved_by: Optional[AdminUser] = None,
|
||||
image_path: Optional[str] = None,
|
||||
):
|
||||
if not dt_submitted:
|
||||
dt_submitted = datetime.now()
|
||||
if not dt_updated:
|
||||
dt_updated = datetime.now()
|
||||
|
||||
if not email and not phone:
|
||||
raise ValueError("One of email or phone must be provided")
|
||||
|
||||
new_job = super().create(
|
||||
title=title,
|
||||
content=content,
|
||||
company=company,
|
||||
location=location,
|
||||
contact_info=contact_info,
|
||||
email=email,
|
||||
phone=phone,
|
||||
summary=summary,
|
||||
dt_submitted=dt_submitted,
|
||||
dt_updated=dt_updated,
|
||||
dt_published=dt_published,
|
||||
state=state,
|
||||
approved_by=approved_by,
|
||||
image_path=image_path,
|
||||
)
|
||||
new_job.save()
|
||||
return new_job
|
||||
|
||||
|
||||
class JobPost_Admin(ModelView):
|
||||
model_class = JobPost
|
||||
column_list = ("state", "title", "dt_published")
|
||||
column_default_sort = ("id", True)
|
||||
|
||||
def is_accessible(self):
|
||||
return current_user.is_authenticated
|
||||
|
||||
|
||||
if not JobPost.table_exists():
|
||||
JobPost.create_table()
|
|
@ -5,13 +5,11 @@ from peewee import CharField
|
|||
from peewee import ForeignKeyField
|
||||
|
||||
from afpy.models import BaseModel
|
||||
from afpy.models.JobPost import JobPost
|
||||
from afpy.models.NewsEntry import NewsEntry
|
||||
|
||||
|
||||
class Slug(BaseModel):
|
||||
url = CharField(null=False, help_text="From URL", verbose_name="From URL", unique=True, index=True)
|
||||
jobpost = ForeignKeyField(JobPost, backref="slug", null=True)
|
||||
newsentry = ForeignKeyField(NewsEntry, backref="slug", null=True)
|
||||
canonical = BooleanField(default=True)
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ from afpy.forms.auth import ChangePasswordForm
|
|||
from afpy.forms.auth import LoginForm
|
||||
from afpy.forms.auth import RegistrationForm
|
||||
from afpy.models.AdminUser import AdminUser
|
||||
from afpy.models.JobPost import JobPost
|
||||
from afpy.models.NewsEntry import NewsEntry
|
||||
|
||||
|
||||
|
@ -129,11 +128,6 @@ class _ModerateView(admin.BaseView):
|
|||
return redirect(url_for(".moderate_view"))
|
||||
|
||||
|
||||
class JobsModerateView(_ModerateView):
|
||||
model = JobPost
|
||||
edit_view = "jobpost.edit_view"
|
||||
|
||||
|
||||
class NewsModerateView(_ModerateView):
|
||||
model = NewsEntry
|
||||
edit_view = "newsentry.edit_view"
|
||||
|
|
|
@ -8,7 +8,6 @@ from flask import render_template
|
|||
from flask import send_from_directory
|
||||
from peewee import DoesNotExist
|
||||
|
||||
from afpy.models.JobPost import JobPost
|
||||
from afpy.models.NewsEntry import NewsEntry
|
||||
from afpy import config
|
||||
|
||||
|
@ -56,9 +55,6 @@ def status():
|
|||
"actualites": {
|
||||
"waiting": NewsEntry.select().where(NewsEntry.state == "waiting").count(),
|
||||
},
|
||||
"emplois": {
|
||||
"waiting": JobPost.select().where(JobPost.state == "waiting").count(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,33 +18,15 @@ jobs_bp = Blueprint("jobs", __name__)
|
|||
|
||||
@jobs_bp.route("/emplois/<int:post_id>")
|
||||
def jobs_render(post_id: int):
|
||||
try:
|
||||
job = JobPost.get_by_id(post_id)
|
||||
except DoesNotExist:
|
||||
abort(404)
|
||||
return render_template("pages/job.html", body_id="emplois", job=job, name=job.title)
|
||||
return redirect("https://discuss.afpy.org/c/emplois/14")
|
||||
|
||||
|
||||
@jobs_bp.route("/emplois")
|
||||
@jobs_bp.route("/emplois/page/<int:current_page>")
|
||||
def jobs_page(current_page: int = 1):
|
||||
total_pages = (JobPost.select().where(JobPost.state == "published").count() // config.NEWS_PER_PAGE) + 1
|
||||
jobs = (
|
||||
JobPost.select()
|
||||
.where(JobPost.state == "published")
|
||||
.order_by(JobPost.dt_submitted.desc())
|
||||
.paginate(current_page, config.NEWS_PER_PAGE)
|
||||
)
|
||||
return render_template(
|
||||
"pages/jobs.html",
|
||||
body_id="emplois",
|
||||
jobs=jobs,
|
||||
title="Offres d'emploi",
|
||||
current_page=current_page,
|
||||
total_pages=total_pages,
|
||||
)
|
||||
return redirect("https://discuss.afpy.org/c/emplois/14")
|
||||
|
||||
|
||||
@jobs_bp.route("/emplois/new", methods=["GET"])
|
||||
def new_job():
|
||||
return render_template("pages/edit_job.html")
|
||||
return redirect("https://discuss.afpy.org/c/emplois/14")
|
||||
|
|
|
@ -6,8 +6,8 @@ from flask import abort
|
|||
from flask import Blueprint
|
||||
from flask import render_template
|
||||
from flask import url_for
|
||||
from flask import redirect
|
||||
|
||||
from afpy.models.JobPost import JobPost
|
||||
from afpy.models.NewsEntry import NewsEntry
|
||||
from afpy import config
|
||||
|
||||
|
@ -20,8 +20,7 @@ def feed_rss(type):
|
|||
name = ""
|
||||
entries = []
|
||||
if type == "emplois":
|
||||
name = "Emplois"
|
||||
entries = JobPost.select().where(JobPost.state == "published")
|
||||
return redirect("https://discuss.afpy.org/c/emplois/14.rss")
|
||||
elif type == "actualites":
|
||||
name = "Actualités"
|
||||
entries = NewsEntry.select().where(NewsEntry.state == "published")
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
(url_for('home.home_page'), 'index', 'Accueil'),
|
||||
(url_for('home.render_rest', name='a-propos'), 'a-propos', 'Qui sommes-nous ?'),
|
||||
(url_for('posts.posts_page'), 'actualites', 'Actualités'),
|
||||
(url_for('jobs.jobs_page'), 'emplois', 'Offres d\'emplois'),
|
||||
("https://discuss.afpy.org/c/emplois/14", 'emplois', 'Offres d\'emplois'),
|
||||
(url_for('home.community_page'), 'communaute', 'Communauté'),
|
||||
('https://discuss.afpy.org', 'discussion', 'Discussion'),
|
||||
('https://www.afpy.org/discord', 'discord', 'Discord'),
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{% if current_user.is_authenticated %}
|
||||
<h1>AFPy Backend Admin</h1>
|
||||
<p class="lead">
|
||||
Bienvenue dans le backoffice de l'AFPy. Vous avez accès à la création, modification et suppression d'articles, jobs et admins, ainsi qu'aux tables.<br>
|
||||
Bienvenue dans le backoffice de l'AFPy. Vous avez accès à la création, modification et suppression d'articles et admins, ainsi qu'aux tables.<br>
|
||||
Ne touchez à rien si vous ne savez pas ce que vous faites.
|
||||
</p>
|
||||
{% else %}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
{% extends '_parts/base.jinja2' %}
|
||||
|
||||
{% block header %}
|
||||
<h1>Création d'un job</h1>
|
||||
{% endblock header %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
<article>
|
||||
<h2>Pour plus de visibilité, la job board de l'AFPy bouge ici : <a href="https://discuss.afpy.org/c/emplois/14">https://discuss.afpy.org/c/emplois</a> !</h2>
|
||||
<p>
|
||||
Pour créer une offre d'emploi là bas, deux solutions :<br/>
|
||||
<ul>
|
||||
<li>Envoyer un email à jobs at afpy point org, le titre de votre offre en sujet, le message de votre offre en corps de message, c'est tout.</li>
|
||||
<li>Publier l'offre directement <a href="https://discuss.afpy.org">sur le forum</a>, dans la catégorie « <a href="https://discuss.afpy.org/c/emplois/14">Offres d'emploi</a> » en cliquant sur le bouton « Créer un sujet »</li>
|
||||
</ul>
|
||||
</p>
|
||||
<h2>C'est quoi https://discuss.afpy.org?</h2>
|
||||
<p>
|
||||
C'est une instance de <a href="https://discourse.org">Discourse</a>, un forum <a href="https://github.com/discourse/discourse">open source</a> qu'on héberge en france chez <a href="https://www.gandi.net/fr">Gandi</a>.
|
||||
</p>
|
||||
</article>
|
||||
{% endblock main %}
|
|
@ -1,51 +0,0 @@
|
|||
{% extends '_parts/base.jinja2' %}
|
||||
|
||||
{% block header %}
|
||||
<h1>{{ job.title }}</h1>
|
||||
{% endblock header %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
{% if preview %}
|
||||
<a href="{{ url_for("jobs_moderation.moderate_view") }}">Retour à l'interface d'administration</a>
|
||||
{# <p><a class="btn btn-warning" href="http://127.0.0.1:5000/admin/jobpost/edit/?id={{ job.id }}" role="button">Edit</a></p>#}
|
||||
{% endif %}
|
||||
|
||||
<article>
|
||||
{% if preview %}
|
||||
<time pubdate datetime="">
|
||||
Pas publié
|
||||
</time>
|
||||
{% else %}
|
||||
<time pubdate datetime="{{ job.dt_published }}">
|
||||
Posté le {{ job.dt_published.strftime('%d/%m/%Y') }} à {{ job.dt_published.strftime('%H:%M:%S') }}
|
||||
</time>
|
||||
{% endif %}
|
||||
<p>
|
||||
<em>
|
||||
{{ job.summary | safe if job.summary }}
|
||||
</em>
|
||||
</p>
|
||||
{% if job.image_path %}
|
||||
<img src="{{ url_for('home.get_image', path=job.image_path) }}" alt="{{ job.title }}" />
|
||||
{% endif %}
|
||||
{{ job.content | md2html | safe }}
|
||||
<aside>
|
||||
<h2>{{ job.company or "(Société inconnue)" }}</h2>
|
||||
<dl>
|
||||
<dt>Adresse</dt>
|
||||
<dd>{{ job.location }}</dd>
|
||||
<dt>Personne à contacter</dt>
|
||||
<dd>{{ job.contact_info }}</dd>
|
||||
{% if job.phone %}
|
||||
<dt>Téléphone</dt>
|
||||
<dd><a href="tel:{{ job.phone }}">{{ job.phone }}</a></dd>
|
||||
{% endif %}
|
||||
{% if job.email %}
|
||||
<dt>Adresse e-mail</dt>
|
||||
<dd><a href="mailto:{{ job.email }}">{{ job.email }}</a></dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</aside>
|
||||
</article>
|
||||
{% endblock main %}
|
|
@ -1,41 +0,0 @@
|
|||
{% extends '_parts/base.jinja2' %}
|
||||
|
||||
{% block header %}
|
||||
<h1>{{ title }}</h1>
|
||||
{% endblock header %}
|
||||
|
||||
{% block main %}
|
||||
<aside>
|
||||
<h2>Pour plus de visibilité, la job board de l'AFPy bouge ici : <a href="https://discuss.afpy.org/c/emplois/14">https://discuss.afpy.org/c/emplois</a> !</h2>
|
||||
<p>
|
||||
Pour créer une offre d'emploi là bas, deux solutions :<br/>
|
||||
<ul>
|
||||
<li>Envoyer un email à jobs at afpy point org, le titre de votre offre en sujet, le message de votre offre en corps de message, c'est tout.</li>
|
||||
<li>Publier l'offre directement <a href="https://discuss.afpy.org">sur le forum</a>, dans la catégorie « <a href="https://discuss.afpy.org/c/emplois/14">Offres d'emploi</a> » en cliquant sur le bouton « Créer un sujet »</li>
|
||||
</ul>
|
||||
</p>
|
||||
</aside>
|
||||
{% for job in jobs %}
|
||||
<article>
|
||||
<h2>{{ job.title }}</h2>
|
||||
<time pubdate datetime="{{ job.dt_published }}">
|
||||
{{ job.dt_published.strftime('%d/%m/%Y') }}
|
||||
</time>
|
||||
{% if job.image_path %}
|
||||
<img src="{{ url_for('home.get_image', path=job.image_path) }}" alt="{{ job.title }}" />
|
||||
{% endif %}
|
||||
{% if job.summary %}{{ job.summary |safe }}{% else %}{{ job.content|truncate(50)|safe }}{% endif %}
|
||||
<p><a href="{{ job|slug_url }}">Lire la suite…</a></p>
|
||||
</article>
|
||||
{% endfor %}
|
||||
|
||||
<aside>
|
||||
{% if current_page != 1 %}
|
||||
<a href="{{ url_for('jobs.jobs_page', current_page=(current_page - 1)) }}">Précedente</a>
|
||||
{% endif %}
|
||||
Page {{ current_page }}/{{ total_pages }}
|
||||
{% if current_page != total_pages %}
|
||||
<a href="{{ url_for('jobs.jobs_page', current_page=(current_page + 1)) }}">Suivante</a>
|
||||
{% endif %}
|
||||
</aside>
|
||||
{% endblock main %}
|
|
@ -7,7 +7,6 @@
|
|||
{% block main %}
|
||||
{% if preview %}
|
||||
<a href="{{ url_for("news_moderation.moderate_view") }}">Retour à l'interface d'administration</a>
|
||||
{# <p><a class="btn btn-warning" href="http://127.0.0.1:5000/admin/jobpost/edit/?id={{ post.id }}" role="button">Edit</a></p>#}
|
||||
{% endif %}
|
||||
|
||||
<article>
|
||||
|
|
|
@ -8,11 +8,7 @@
|
|||
<item>
|
||||
<title><![CDATA[ {{ entry.title | safe }} ]]></title>
|
||||
<description><![CDATA[ {{ (entry.description or entry.summary) | safe }} ]]></description>
|
||||
{% if type == "emplois" %}
|
||||
<link>{{ url_for("jobs.jobs_render", post_id=entry.id, _external=True) }}</link>
|
||||
{% else %}
|
||||
<link>{{ url_for("posts.post_render", post_id=entry.id, _external=True) }}</link>
|
||||
{% endif %}
|
||||
<pubDate>{{ entry.dt_published }}</pubDate>
|
||||
</item>
|
||||
{% endfor %}
|
||||
|
|
31
xml2sql.py
31
xml2sql.py
|
@ -8,16 +8,14 @@ from dateutil.parser import parse
|
|||
from html2text import html2text
|
||||
|
||||
from afpy.models.AdminUser import AdminUser
|
||||
from afpy.models.JobPost import JobPost
|
||||
from afpy.models.NewsEntry import NewsEntry
|
||||
from afpy.models.Slug import Slug
|
||||
|
||||
PAGINATION = 12
|
||||
|
||||
CATEGORY_ACTUALITIES = "actualites"
|
||||
CATEGORY_JOBS = "emplois"
|
||||
|
||||
CATEGORIES = {CATEGORY_ACTUALITIES: "Actualités", CATEGORY_JOBS: "Offres d’emploi"}
|
||||
CATEGORIES = {CATEGORY_ACTUALITIES: "Actualités"}
|
||||
|
||||
STATE_WAITING = "waiting"
|
||||
STATE_PUBLISHED = "published"
|
||||
|
@ -110,30 +108,3 @@ if __name__ == "__main__":
|
|||
post_id = post.get("id")
|
||||
if post_id:
|
||||
Slug.create(url=post_id.split("afpy.org")[-1], newsentry=new_post)
|
||||
else:
|
||||
email = post.get("email", "")
|
||||
phone = post.get("phone", "")
|
||||
if not email and not phone:
|
||||
phone = "(no phone)"
|
||||
new_job = JobPost.create(
|
||||
title=post.get("title", "(untitled)"),
|
||||
summary=post.get("summary"),
|
||||
content=html2text(post.get("content", "")),
|
||||
company=post.get("company", ""),
|
||||
email=email,
|
||||
phone=phone,
|
||||
location=post.get("address", ""),
|
||||
contact_info=post.get("contact", ""),
|
||||
dt_published=parse(post.get("published")).replace(tzinfo=None)
|
||||
if state == "published"
|
||||
else None,
|
||||
dt_submitted=parse(post.get("published")).replace(tzinfo=None),
|
||||
dt_updated=parse(post.get("published")).replace(tzinfo=None),
|
||||
state=state,
|
||||
approved_by=admin_1 if state == "published" or state == "rejected" else None,
|
||||
image_path=post.get("image"),
|
||||
)
|
||||
Slug.create(url=f"/posts/emplois/{post.get(FIELD_TIMESTAMP)}", jobpost=new_job)
|
||||
post_id = post.get("id")
|
||||
if post_id:
|
||||
Slug.create(url=post_id.split("afpy.org")[-1], jobpost=new_job)
|
||||
|
|
Loading…
Reference in New Issue
Block a user