Drop unused jobs page.

Last job was posted on january 2022, 10 month ago.
This commit is contained in:
Julien Palard 2022-11-17 12:02:00 +01:00
parent 1da49c227e
commit 754f4178d3
Signed by: mdk
GPG Key ID: 0EFC1AC1006886F8
16 changed files with 10 additions and 335 deletions

View File

@ -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,10 +101,7 @@ 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)
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)

View File

@ -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)")

View File

@ -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()

View File

@ -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)

View File

@ -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"

View File

@ -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(),
},
}

View File

@ -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")

View File

@ -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")

View File

@ -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'),

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}
<link>{{ url_for("posts.post_render", post_id=entry.id, _external=True) }}</link>
<pubDate>{{ entry.dt_published }}</pubDate>
</item>
{% endfor %}

View File

@ -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 demploi"}
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)