def post(cls):
        """Creates one activity in the database.

        Args:
            activity_type (str): Body argument indicating the activity type
            site (str): Body argument indicating the factory location
            typology (str): Body argument indicating the context of the activity
            description (str): Body argument indicating the description of the activity
            estimated_time (int): Body argument indicating the expected duration of the activity, in minutes
            interruptible (bool): Body argument indicating if the activity should be interruptible
            materials (str, optional): Optional body argument indicating the list of materials needed for the activity
            week (int): Body argument indicating the nth week of the year during which the activity has to be performed
            workspace_notes (str, optional): Optional body argument indicating a short description of the workspace

        Returns:
            dict of (str, any): Jsonified activity or error message.
        """
        data = cls._activity_parser.parse_args()

        try:
            activity = MaintenanceActivityModel(**data)
            activity.save_to_db()
        except Exception as e:
            return {"error": str(e)}, 500

        return activity.json(), 201
Example #2
0
def test_no_activities_page_not_found(app, planner_client, maintainer_users,
                                      activity_seed):
    """ Tests a failed retrival of the weekly availabilities given a non-existing current_page """

    with app.app_context():
        # Create one unassigned activity
        activity = MaintenanceActivityModel(**activity_seed)
        activity.save_to_db()

    test_current_page = 3
    test_page_size = len(maintainer_users)
    data = {"current_page": test_current_page, "page_size": test_page_size}

    res = planner_client.get(
        f"/maintainer/{activity_seed['activity_id']}/availabilities",
        data=data)

    assert res.status_code == 404
    assert "message" in res.get_json().keys()
def setup(app, activity_seeds, planner_seed):
    """Before each test it drops every table and recreates them. 
    Then it creates an activity for every dictionary present in activity_seeds
    It also creates a planner that will be used to perform the requests

    Returns:
        boolean: the return status
    """
    with app.app_context():
        from db import db
        db.drop_all()
        db.create_all()
        from models.maintenance_activity import MaintenanceActivityModel
        for seed in activity_seeds:
            activity = MaintenanceActivityModel(**seed)
            activity.save_to_db()
        from models.user import UserModel
        planner = UserModel(**planner_seed)
        planner.save_to_db()
    return True
    def get(cls):
        """Gets a paginated list of activites, along with its metadata. Takes current_page and page_size as optional body arguments.

        Args:
            current_page (int, optional): Body param indicating the requested page. Defaults to 1.
            page_size (int, optional): Body param indicating the page size. Defaults to 10.

        Returns:
            dict of (str, any): Json of rows and meta. Rows is the list of paginated activities; meta is its metadata;
        """
        data = cls._activity_parser.parse_args()
        rows, meta = [], {}
        if data["week"]:
            rows, meta = MaintenanceActivityModel.find_some_in_week(
                **data)
        else:
            rows, meta = MaintenanceActivityModel.find_some(
                data["current_page"], data["page_size"])

        return {"rows": [activity.json() for activity in rows], "meta": meta}, 200
Example #5
0
        def _calculate_daily_percentage_availability(self):
            """Private method used to calculate the user's percentage availability for a whole day

            Returns:
                (str): A string representing the percentage availability for an user in a whole day.
            """
            activities = self.user.get_daily_activities(
                self.week, self.week_day, self.exclude)
            busy_minutes = MaintenanceActivityModel.get_total_estimated_time(
                activities)
            busy_hours = busy_minutes / 60
            return f"{ round(100 - ( 100 * busy_hours/self.user.work_hours)) }%"
Example #6
0
def test_no_activities_success(app, planner_client, maintainer_users,
                               activity_seed, week_days):
    """ Tests a successful retrival of the weekly availabilities for a maintainer
    when there is no maintenance activity stored in the database
    """

    with app.app_context():
        # Create one unassigned activity
        activity = MaintenanceActivityModel(**activity_seed)
        activity.save_to_db()

    test_current_page = 1
    test_page_size = len(maintainer_users) - 1
    data = {"current_page": test_current_page, "page_size": test_page_size}

    res = planner_client.get(
        f"/maintainer/{activity_seed['activity_id']}/availabilities",
        data=data)

    validate_successful_response(res, test_current_page, test_page_size,
                                 maintainer_users, activity_seed, week_days)
    def get(cls, id):
        """Gets one activity from database based on given id.
            Fails if there is no activity with that id.

        Args:
            id (int): The identifier of the maintenance activity to be retrieved.

        Returns:
            dict of (str, any): Jsonified activity or error message.
        """
        try:
            activity = MaintenanceActivityModel.find_by_id(id)
        except Exception as e:
            return {"error": str(e)}, 500

        if not activity:
            return {"message": "Activity not found"}, 404
        return activity.json(), 200
Example #8
0
    def get_daily_activities(self, week, week_day, exclude=None):
        """Finds every activity for a user with role 'maintainer' in a given day.

        Args:
            week (int): The nth week of the year
            week_day (str): The day of the week (i.e.: monday, tuesday, ...)
            exclude (int, optional): a valid identifier for an activity that has to be assigned

        Raises:
            RoleError: If the user's role is not 'maintainer'

        Returns:
            list of (MaintenanceActivityModel): List of found Maintenance Activities
        """
        if(self.role != "maintainer"):
            raise RoleError(
                "The user is not a maintaner, therefore it does not have availabilities")
        return MaintenanceActivityModel.find_all_in_day_for_user(
            self.username, week, week_day, exclude)
    def delete(cls, id):
        """Deletes one activity from database based on given id.
            Fails if there is no activity with that id.

        Args:
            id (int): The identifier of the activity to be deleted.

        Returns:
            dict of (str, any): Confirmation or error message.
        """
        try:
            activity = MaintenanceActivityModel.find_by_id(id)
            if not activity:
                return {"message": "Activity not found"}, 404
            activity.delete_from_db()

        except Exception as e:
            return {"error": str(e)}, 500

        return {"message": "Activity deleted"}, 200
Example #10
0
    def can_do_activity(self, activity_id, week_day, start_time):
        """Checks if a new activity can be inserted in the user's schedule given his time left in his DailyAgenda

        Raises:
            RoleError: If the user's role is not 'maintainer'
            InvalidAgendaError: If the user does not have enough time to perform the maintenance activities

        Args:
            activity_id (int): The id for the new activity that has to be inserted
            start_time (int): The hour that the activity has to be scheduled to
            week_day (str): The day of the week (i.e.: monday, tuesday, ...)

        Returns:
            (bool, str): A tuple that contains a boolean that tells if the answer is insertable, and a string
            that tells a message about the obtained response 
        """
        activity = MaintenanceActivityModel.find_by_id(activity_id)
        if not activity:
            return False, "Activity not found"
        daily_agenda = self.DailyAgenda(
            self, activity.week, week_day, exclude=activity_id)
        return daily_agenda.is_activity_insertable(activity_id, start_time)
    def put(cls, id):
        """Edits one activity in the database based on given id.
            Fails if there is no activity with that id.

        Args:
            id (int): The identifier of the activity to be edited.
            workspace_notes (str): Body param indicating the new workspace notes.

        Returns:
            dict of (str, any): Jsonified activity or error message.
        """
        data = cls._activity_parser.parse_args()
        try:
            activity = MaintenanceActivityModel.find_by_id(id)

            if not activity:
                return {"message": "Activity not found"}, 404

            activity.update_and_save(data)
        except Exception as e:
            return {"error": str(e)}, 500
        return activity.json(), 200
    def get(cls, username):
        """Gets the public representation of the DailyAgenda for a user with given username based on the week associated with
        the activity with given activity_id and the given week_day.
        Fails if the user's role is not 'maintainer'

        Args:
            username (str): A valid username
            activity_id (int): Body param indicating the identifier of the maintenance activity to be assigned.
            week_day (str): Body param indicating the day of the week (i.e.: monday, tuesday, ...)


        Returns:
            dict of (str, any): Json representing the user's availabilities in minutes classified by hour or an error message.
        """
        agenda = None
        try:
            user: UserModel = UserModel.find_by_username(username)
            if not user:
                return {"message": "User not found"}, 404

            if user.role != "maintainer":
                return {
                    "message":
                    "User role for user with given username is not 'maintainer'"
                }, 400

            data = cls._activity_parser.parse_args()
            activity = MaintenanceActivityModel.find_by_id(data["activity_id"])
            if not activity:
                return {"message": "Activity not found"}, 404

            agenda = user.get_daily_agenda(activity.week,
                                           data["week_day"],
                                           exclude=data["activity_id"])
        except Exception as e:
            return {"error": str(e)}, 500

        return agenda.json(), 200
    def put(cls, id):
        """Assigns a MaintenanceActivity to an user with role 'maintainer'.
        Fails if the maintainer role is not 'maintainer'.

        Args:
            id (int): The identifier of the maintenance activity to be assigned.
            maintainer_username (str): Body param indicating the maintainer's username
            week_day (str): Body param indicating the day of the week (i.e.: monday, tuesday, ...)
            start_time (int): Body param indicating the hour that the activity has to be scheduled to

        Returns:
            dict of (str, str): Jsonified success or error message.
        """
        data = cls._activity_parser.parse_args()

        try:
            activity = MaintenanceActivityModel.find_by_id(id)
            if not activity:
                return {"message": "Activity not found"}, 404

            user = UserModel.find_by_username(data["maintainer_username"])
            if not user:
                return {"message": "User not found"}, 404

            if user.role != "maintainer":
                return {"message": "User role for user with given username is not 'maintainer'"}, 400

            is_doable, reason = user.can_do_activity(
                id, data["week_day"], data["start_time"])
            if not is_doable:
                return {"message": reason}, 400

            activity.update_and_save(data)

        except Exception as e:
            return {"error": str(e)}, 500

        return {"message": "Activity assigned successfully"}, 200
Example #14
0
        def is_activity_insertable(self, activity_id, start_time):
            """Checks if a new activity can be inserted in the user's schedule given his time left in the DailyAgenda

            Args:
                activity_id (int): The id for the new activity that has to be inserted
                start_time (int): The hour that the activity has to be scheduled to

            Returns:
                (bool, str): A tuple that contains a boolean that tells if the answer is insertable, and a string
                that tells a message about the obtained response 
            """
            if start_time < self.user.work_start_hour or start_time > self.user.work_start_hour + self.user.work_hours:
                return False, "Invalid start_time"
            activity = MaintenanceActivityModel.find_by_id(activity_id)
            if not activity:
                return False, "Activity not found"

            activity.start_time = start_time
            try:
                self._calculate_agenda_dictionary(append=activity)
                return True, "Ok"
            except InvalidAgendaError as e:
                return False, e.message
    def get(cls, activity_id):
        """Gets a paginated list of Maintainers weekly availability, along with its metadata.
        For every user it returns aswell the user itself, the user's skill compliance (expressed as a fraction) 
        with the next activity that the planner wants to assign and the week in which the
        activity has to be assigned

        Args:
            activity_id (int): The identifier of the maintenance activity to be assigned.
            current_page (int, optional): Body param indicating the requested page. Defaults to 1.
            page_size (int, optional): Body param indicating the page size. Defaults to 10.

        Returns:
            dict of (str, any): Json of rows and meta or an error message. Rows is the list of paginated users' informations; meta is its metadata.
        """

        activity = MaintenanceActivityModel.find_by_id(activity_id)
        if not activity:
            return {"message": "Activity not found"}, 404

        data = cls._activity_parser.parse_args()
        rows, meta = UserModel.find_some_maintainers(**data)

        return {
            "rows": [{
                "user":
                user.json(),
                "skill_compliance":
                "3/5",
                "weekly_percentage_availability":
                user.get_weekly_percentage_availability(
                    activity.week, exclude=activity_id).json(),
                "week":
                activity.week
            } for user in rows],
            "meta":
            meta
        }, 200
Example #16
0
def test_full_activities_success(app, planner_client, maintainer_user,
                                 maintainer_users, activity_seed,
                                 activity_seed_without_id, week_days):
    """ Tests a successful retrival of the weekly availabilities when a maintainer
    has an already full schedule """
    start_time = config.MAINTAINER_WORK_START_HOUR
    end_time = start_time + config.MAINTAINER_WORK_HOURS

    with app.app_context():
        # Create many assigned activities without filling all the maintainer work schedule
        i = start_time
        while i < end_time:
            activity = MaintenanceActivityModel(**activity_seed_without_id)
            activity.maintainer_username = maintainer_user["username"]
            activity.week_day = "monday"
            activity.start_time = i
            activity.save_to_db()
            i += 1
        # Create one unassigned activity
        activity = MaintenanceActivityModel(**activity_seed)
        activity.save_to_db()

    test_current_page = 1
    test_page_size = len(maintainer_users)
    data = {"current_page": test_current_page, "page_size": test_page_size}

    res = planner_client.get(
        f"/maintainer/{activity_seed['activity_id']}/availabilities",
        data=data)

    validate_successful_response(res, test_current_page, test_page_size,
                                 maintainer_users, activity_seed, week_days)

    maintainer_availability = next(
        row["weekly_percentage_availability"] for row in res.get_json()["rows"]
        if row["user"]["username"] == maintainer_user["username"])

    assert maintainer_availability["monday"] == "0%"
Example #17
0
def test_full_activities_reassign(app, planner_client, maintainer_user,
                                  maintainer_users, activity_seed,
                                  activity_seed_without_id, week_days):
    """ Tests a successful retrival of the weekly availabilities when a maintainer
        already has a full schedule and the activity is already associated with that maintainer"""

    start_time = config.MAINTAINER_WORK_START_HOUR
    end_time = start_time + config.MAINTAINER_WORK_HOURS

    with app.app_context():
        work_hours = config.MAINTAINER_WORK_HOURS
        i = start_time
        while i < end_time - 1:
            activity = MaintenanceActivityModel(**activity_seed_without_id)
            activity.maintainer_username = maintainer_user["username"]
            activity.week_day = "monday"
            activity.start_time = i
            activity.save_to_db()
            i += 1
        activity = MaintenanceActivityModel(**activity_seed)
        activity.maintainer_username = maintainer_user["username"]
        activity.week_day = "monday"
        activity.start_time = i
        activity.save_to_db()

    test_current_page = 1
    test_page_size = len(maintainer_users)
    data = {"current_page": test_current_page, "page_size": test_page_size}

    res = planner_client.get(
        f"/maintainer/{activity_seed['activity_id']}/availabilities",
        data=data)

    validate_successful_response(res, test_current_page, test_page_size,
                                 maintainer_users, activity_seed, week_days)

    maintainer_availability = next(
        row["weekly_percentage_availability"] for row in res.get_json()["rows"]
        if row["user"]["username"] == maintainer_user["username"])

    assert maintainer_availability[
        "monday"] == f"{round(100 - 100*(work_hours-1)/work_hours)}%"