diff --git a/flaschengeist/plugins/auth_ldap/__init__.py b/flaschengeist/plugins/auth_ldap/__init__.py index ebe84c3..29659bf 100644 --- a/flaschengeist/plugins/auth_ldap/__init__.py +++ b/flaschengeist/plugins/auth_ldap/__init__.py @@ -114,7 +114,7 @@ class AuthLDAP(AuthPlugin): } ) if user.display_name: - attributes.update( {"displayName": user.display_name}) + attributes.update({"displayName": user.display_name}) ldap_conn.add(dn, self.object_classes, attributes) self._set_roles(user) self.update_user(user) diff --git a/flaschengeist/plugins/events/event_controller.py b/flaschengeist/plugins/events/event_controller.py index 4cd2d03..432a5a8 100644 --- a/flaschengeist/plugins/events/event_controller.py +++ b/flaschengeist/plugins/events/event_controller.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta, timezone from enum import IntEnum -from typing import Optional +from typing import Optional, Tuple from werkzeug.exceptions import BadRequest, Conflict, NotFound from sqlalchemy.exc import IntegrityError @@ -147,7 +147,7 @@ def get_events( offset: Optional[int] = None, descending: Optional[bool] = False, with_backup=False, -): +) -> Tuple[int, list[Event]]: """Query events which start from begin until end Args: start (datetime): Earliest start @@ -161,10 +161,14 @@ def get_events( query = query.filter(start <= Event.start) if end is not None: query = query.filter(Event.start < end) + elif start is None: + # Neither start nor end was given + query = query.filter(datetime.now() <= Event.start) if descending: query = query.order_by(Event.start.desc()) else: query = query.order_by(Event.start) + count = query.count() if limit is not None: query = query.limit(limit) if offset is not None and offset > 0: @@ -173,7 +177,7 @@ def get_events( if not with_backup: for event in events: clear_backup(event) - return events + return count, events def delete_event(event_id): @@ -221,6 +225,24 @@ def get_job(job_id, event_id=None) -> Job: return job +def get_jobs(user, start=None, end=None, limit=None, offset=None, descending=None) -> Tuple[int, list[Job]]: + query = Job.query.join(Service).filter(Service.user_ == user) + if start is not None: + query = query.filter(start <= Job.end) + if end is not None: + query = query.filter(end >= Job.start) + if descending is not None: + query = query.order_by(Job.start.desc(), Job.type_id_) + else: + query = query.order_by(Job.start, Job.type_id_) + count = query.count() + if limit is not None: + query = query.limit(limit) + if offset is not None: + query = query.offset(offset) + return count, query.all() + + def add_job(event, job_type, required_services, start, end=None, comment=None): job = Job( required_services=required_services, @@ -314,7 +336,16 @@ def respond_invitation(invite: Invitation, accepted=True): raise Conflict if not accepted: - EventPlugin.plugin.notify(inviter, _("Invitation rejected"), {"type": NotifyType.INVITATION_REJECTED, "event": job.event_id_, "job": invite.job_id, "invitee": invite.invitee_id}) + EventPlugin.plugin.notify( + inviter, + _("Invitation rejected"), + { + "type": NotifyType.INVITATION_REJECTED, + "event": job.event_id_, + "job": invite.job_id, + "invitee": invite.invitee_id, + }, + ) else: if invite.transferee_id is None: assign_job(job, invite.invitee_, 1) @@ -324,7 +355,16 @@ def respond_invitation(invite: Invitation, accepted=True): raise Conflict unassign_job(job, invite.transferee_, service[0], True) assign_job(job, invite.invitee_, service[0].value) - EventPlugin.plugin.notify(inviter, _("Invitation accepted"), {"type": NotifyType.INVITATION_ACCEPTED, "event": job.event_id_, "job": invite.job_id, "invitee": invite.invitee_id}) + EventPlugin.plugin.notify( + inviter, + _("Invitation accepted"), + { + "type": NotifyType.INVITATION_ACCEPTED, + "event": job.event_id_, + "job": invite.job_id, + "invitee": invite.invitee_id, + }, + ) @scheduled diff --git a/flaschengeist/plugins/events/models.py b/flaschengeist/plugins/events/models.py index 36fd3f9..97c06ca 100644 --- a/flaschengeist/plugins/events/models.py +++ b/flaschengeist/plugins/events/models.py @@ -58,7 +58,6 @@ class Service(db.Model, ModelSerializeMixin): class Job(db.Model, ModelSerializeMixin): __tablename__ = _table_prefix_ + "job" - _type_id = db.Column("type_id", Serial, db.ForeignKey(f"{_table_prefix_}job_type.id"), nullable=False) id: int = db.Column(Serial, primary_key=True) start: datetime = db.Column(UtcDateTime, nullable=False) @@ -73,6 +72,8 @@ class Job(db.Model, ModelSerializeMixin): event_ = db.relationship("Event", back_populates="jobs") event_id_ = db.Column("event_id", Serial, db.ForeignKey(f"{_table_prefix_}event.id"), nullable=False) + type_id_ = db.Column("type_id", Serial, db.ForeignKey(f"{_table_prefix_}job_type.id"), nullable=False) + invitations_ = db.relationship("Invitation", cascade="all,delete,delete-orphan", back_populates="job_") __table_args__ = (UniqueConstraint("type_id", "start", "event_id", name="_type_start_uc"),) diff --git a/flaschengeist/plugins/events/routes.py b/flaschengeist/plugins/events/routes.py index 2fb9b60..fe7b2f9 100644 --- a/flaschengeist/plugins/events/routes.py +++ b/flaschengeist/plugins/events/routes.py @@ -1,18 +1,14 @@ -from datetime import datetime, timedelta, timezone from http.client import NO_CONTENT -from re import template from flask import request, jsonify -from sqlalchemy import exc from werkzeug.exceptions import BadRequest, NotFound, Forbidden from flaschengeist.models.session import Session -from flaschengeist.plugins.events.models import Job from flaschengeist.utils.decorators import login_required from flaschengeist.utils.datetime import from_iso_format from flaschengeist.controller import userController from . import event_controller, permissions, EventPlugin -from ...utils.HTTP import no_content +from ...utils.HTTP import get_filter_args, no_content def dict_get(self, key, default=None, type=None): @@ -194,63 +190,12 @@ def get_event(event_id, current_session): @EventPlugin.blueprint.route("/events", methods=["GET"]) @login_required() -def get_filtered_events(current_session): - begin = request.args.get("from", type=from_iso_format) - end = request.args.get("to", type=from_iso_format) - limit = request.args.get("limit", type=int) - offset = request.args.get("offset", type=int) - descending = "descending" in request.args - if begin is None and end is None: - begin = datetime.now() - return jsonify( - event_controller.get_events( - start=begin, - end=end, - limit=limit, - offset=offset, - descending=descending, - with_backup=current_session.user_.has_permission(permissions.SEE_BACKUP), - ) +def get_events(current_session): + count, result = event_controller.get_events( + *get_filter_args(), + with_backup=current_session.user_.has_permission(permissions.SEE_BACKUP), ) - - -@EventPlugin.blueprint.route("/events//", methods=["GET"]) -@EventPlugin.blueprint.route("/events///", methods=["GET"]) -@login_required() -def get_events(current_session, year=datetime.now().year, month=datetime.now().month, day=None): - """Get Event objects for specified date (or month or year), - if nothing set then events for current month are returned - - Route: ``/events[//[/]]`` | Method: ``GET`` - - Args: - year (int, optional): year to query, defaults to current year - month (int, optional): month to query (if set), defaults to current month - day (int, optional): day to query events for (if set) - current_session: Session sent with Authorization Header - - Returns: - JSON encoded list containing events found or HTTP-error - """ - try: - begin = datetime(year=year, month=month, day=1, tzinfo=timezone.utc) - if day: - begin += timedelta(days=day - 1) - end = begin + timedelta(days=1) - else: - if month == 12: - end = datetime(year=year + 1, month=1, day=1, tzinfo=timezone.utc) - else: - end = datetime(year=year, month=month + 1, day=1, tzinfo=timezone.utc) - - events = event_controller.get_events( - begin, - end, - with_backup=current_session.user_.has_permission(permissions.SEE_BACKUP), - ) - return jsonify(events) - except ValueError: - raise BadRequest("Invalid date given") + return jsonify({"count": count, "result": result}) def _add_job(event, data): @@ -449,6 +394,13 @@ def update_job(event_id, job_id, current_session: Session): return jsonify(job) +@EventPlugin.blueprint.route("/events/jobs", methods=["GET"]) +@login_required() +def get_jobs(current_session: Session): + count, result = event_controller.get_jobs(current_session.user_, *get_filter_args()) + return jsonify({"count": count, "result": result}) + + @EventPlugin.blueprint.route("/events/jobs//assign", methods=["POST"]) @login_required() def assign_job(job_id, current_session: Session): diff --git a/flaschengeist/utils/HTTP.py b/flaschengeist/utils/HTTP.py index 8fe57a9..e81316b 100644 --- a/flaschengeist/utils/HTTP.py +++ b/flaschengeist/utils/HTTP.py @@ -2,6 +2,24 @@ from http.client import NO_CONTENT, CREATED from flask import make_response, jsonify +from flaschengeist.utils.datetime import from_iso_format + + +def get_filter_args(): + """ + Get filter parameter from request + returns: FROM, TO, LIMIT, OFFSET, DESCENDING + """ + from flask import request + + return ( + request.args.get("from", type=from_iso_format), + request.args.get("to", type=from_iso_format), + request.args.get("limit", type=int), + request.args.get("offset", type=int), + "descending" in request.args, + ) + def no_content(): return make_response(jsonify(""), NO_CONTENT)