Esempio n. 1
0
 def shortname(self) -> str:
     """
     Returns the task's shortname.
     """
     d = tablename_to_task_class_dict()
     taskclass = d[self.task_table_name]
     return taskclass.shortname
Esempio n. 2
0
def task_factory_unfiltered(dbsession: SqlASession,
                            basetable: str,
                            serverpk: int) -> Optional[Task]:
    """
    Load a task from the database and return it.
    No permission filtering is performed. (Used by
    :class:`camcops_server.cc_modules.cc_taskindex.TaskIndexEntry`.)

    Args:
        dbsession: a :class:`sqlalchemy.orm.session.Session`
        basetable: name of the task's base table
        serverpk: server PK of the task

    Returns:
        the task, or ``None`` if the PK doesn't exist

    Raises:
        :exc:`HTTPBadRequest` if the table doesn't exist
    """
    d = tablename_to_task_class_dict()
    try:
        cls = d[basetable]  # may raise KeyError
    except KeyError:
        raise exc.HTTPBadRequest("No such task table: {!r}".format(basetable))
    # noinspection PyProtectedMember
    q = dbsession.query(cls).filter(cls._pk == serverpk)
    return q.first()
Esempio n. 3
0
    def update_task_index_for_upload(
        cls,
        session: SqlASession,
        tablechanges: UploadTableChanges,
        indexed_at_utc: Pendulum,
    ) -> None:
        """
        Updates the index for a device's upload.

        - Deletes index entries for records that are on the way out.
        - Creates index entries for records that are on the way in.
        - Deletes/recreates index entries for records being preserved.

        Args:
            session:
                an SQLAlchemy Session
            tablechanges:
                a :class:`camcops_server.cc_modules.cc_client_api_core.UploadTableChanges`
                object describing the changes to a table
            indexed_at_utc:
                current time in UTC
        """  # noqa
        tasktablename = tablechanges.tablename
        d = tablename_to_task_class_dict()
        try:
            taskclass = d[tasktablename]  # may raise KeyError
        except KeyError:
            fail_user_error(f"Bug: no such task table: {tasktablename!r}")

        # noinspection PyUnresolvedReferences
        idxtable = cls.__table__  # type: Table
        idxcols = idxtable.columns

        # Delete the old.
        delete_index_pks = tablechanges.task_delete_index_pks
        if delete_index_pks:
            log.debug(
                "Deleting old task indexes: {}, server PKs {}",
                tasktablename,
                delete_index_pks,
            )
            # noinspection PyProtectedMember
            session.execute(
                idxtable.delete()
                .where(idxcols.task_table_name == tasktablename)
                .where(idxcols.task_pk.in_(delete_index_pks))
            )

        # Create the new.
        reindex_pks = tablechanges.task_reindex_pks
        if reindex_pks:
            log.debug(
                "Recreating task indexes: {}, server PKs {}",
                tasktablename,
                reindex_pks,
            )
            # noinspection PyUnboundLocalVariable,PyProtectedMember
            q = session.query(taskclass).filter(taskclass._pk.in_(reindex_pks))
            for task in q:
                cls.index_task(task, session, indexed_at_utc=indexed_at_utc)
Esempio n. 4
0
def task_factory(req: "CamcopsRequest", basetable: str,
                 serverpk: int) -> Optional[Task]:
    """
    Load a task from the database and return it.
    Filters to tasks permitted to the current user.

    Args:
        req: the :class:`camcops_server.cc_modules.cc_request.CamcopsRequest`
        basetable: name of the task's base table
        serverpk: server PK of the task

    Returns:
        the task, or ``None`` if the PK doesn't exist

    Raises:
        :exc:`HTTPBadRequest` if the table doesn't exist

    """
    d = tablename_to_task_class_dict()
    try:
        cls = d[basetable]  # may raise KeyError
    except KeyError:
        raise exc.HTTPBadRequest("No such task table: {!r}".format(basetable))
    dbsession = req.dbsession
    # noinspection PyProtectedMember
    q = dbsession.query(cls).filter(cls._pk == serverpk)
    q = task_query_restricted_to_permitted_users(req, q, cls, as_dump=False)
    return q.first()
Esempio n. 5
0
def task_classes_from_table_names(
        tablenames: List[str],
        sortmethod: TaskClassSortMethod = TaskClassSortMethod.NONE) \
        -> List[Type[Task]]:
    """
    Transforms a list of task base tablenames into a list of task classes,
    appropriately sorted.

    Args:
        tablenames: list of task base table names
        sortmethod: a :class:`TaskClassSortMethod` enum

    Returns:
        a list of task classes, in the order requested

    Raises:
        :exc:`KeyError` if a table name is invalid

    """
    d = tablename_to_task_class_dict()
    classes = []  # type: List[Type[Task]]
    for tablename in tablenames:
        cls = d[tablename]
        classes.append(cls)
    sort_task_classes_in_place(classes, sortmethod)
    return classes
Esempio n. 6
0
def task_factory_clientkeys_no_security_checks(
    dbsession: SqlASession,
    basetable: str,
    client_id: int,
    device_id: int,
    era: str,
) -> Optional[Task]:
    """
    Load a task from the database and return it.
    Filters to tasks permitted to the current user.

    Args:
        dbsession: a :class:`sqlalchemy.orm.session.Session`
        basetable: name of the task's base table
        client_id: task's ``_id`` value
        device_id: task's ``_device_id`` value
        era: task's ``_era`` value

    Returns:
        the task, or ``None`` if it doesn't exist

    Raises:
        :exc:`KeyError` if the table doesn't exist
    """
    d = tablename_to_task_class_dict()
    cls = d[basetable]  # may raise KeyError
    # noinspection PyProtectedMember
    q = (
        dbsession.query(cls)
        .filter(cls.id == client_id)
        .filter(cls._device_id == device_id)
        .filter(cls._era == era)
    )
    return q.first()
Esempio n. 7
0
    def task_shortname(self) -> str:
        """
        Short name of the task being scheduled.
        """
        task_class_lookup = tablename_to_task_class_dict()

        return task_class_lookup[self.task_table_name].shortname
Esempio n. 8
0
    def task_ancestor(self) -> Optional["Task"]:
        from camcops_server.cc_modules.cc_task import (
            tablename_to_task_class_dict, )  # noqa  # delayed import

        d = tablename_to_task_class_dict()
        try:
            cls = d[self.tablename]  # may raise KeyError
            return cls.get_linked(self.tablepk, self)
        except KeyError:
            return None
    def _fetch_tasks_from_indexes(self) -> None:
        """
        Takes the query that has already been stored in :attr:`_all_indexes`,
        and populate the task attributes, :attr:`_all_tasks` and
        :attr:`_tasks_by_class`.
        """
        if self._all_tasks is not None:
            return
        assert self._all_indexes is not None

        d = tablename_to_task_class_dict()
        dbsession = self.req.dbsession
        self._all_tasks = []  # type: List[Task]

        # Fetch indexes
        if isinstance(self._all_indexes, Query):
            # Query built, but indexes not yet fetched.
            # Replace the query with actual indexes
            self._all_indexes = (self._all_indexes.all()
                                 )  # type: List[TaskIndexEntry]  # noqa
        indexes = self._all_indexes

        # Fetch tasks
        tablenames = set(index.task_table_name for index in indexes)
        for tablename in tablenames:
            # We do this by task class, so we can execute a single query per
            # task type (rather than per task).
            try:
                taskclass = d[tablename]
            except KeyError:
                log.warning("Bad tablename in index: {!r}", tablename)
                continue
            tasklist = self._tasks_by_class.setdefault(taskclass, [])
            task_pks = [i.task_pk for i in indexes if i.tablename == tablename]
            # noinspection PyProtectedMember
            qtask = dbsession.query(taskclass).filter(
                taskclass._pk.in_(task_pks))
            qtask = self._filter_query_for_text_contents(qtask, taskclass)
            tasks = qtask.all()  # type: List[Task]
            for task in tasks:
                tasklist.append(task)
                self._all_tasks.append(task)

        # Sort tasks
        for tasklist in self._tasks_by_class.values():
            sort_tasks_in_place(tasklist, self._sort_method_by_class)
        sort_tasks_in_place(self._all_tasks, self._sort_method_global)
Esempio n. 10
0
def task_factory_no_security_checks(dbsession: SqlASession, basetable: str,
                                    serverpk: int) -> Optional[Task]:
    """
    Load a task from the database and return it.
    Filters to tasks permitted to the current user.

    Args:
        dbsession: a :class:`sqlalchemy.orm.session.Session`
        basetable: name of the task's base table
        serverpk: server PK of the task

    Returns:
        the task, or ``None`` if the PK doesn't exist

    Raises:
        :exc:`KeyError` if the table doesn't exist
    """
    d = tablename_to_task_class_dict()
    cls = d[basetable]  # may raise KeyError
    # noinspection PyProtectedMember
    q = dbsession.query(cls).filter(cls._pk == serverpk)
    return q.first()
Esempio n. 11
0
    def get_list_of_scheduled_tasks(
            self, req: "CamcopsRequest") -> List[ScheduledTaskInfo]:
        """
        Tasks scheduled for this patient.
        """

        task_list = []

        task_class_lookup = tablename_to_task_class_dict()

        for tsi in self.task_schedule.items:
            start_datetime = None
            end_datetime = None
            task = None

            if self.start_datetime is not None:
                start_datetime = self.start_datetime.add(
                    days=tsi.due_from.days)
                end_datetime = self.start_datetime.add(days=tsi.due_by.days)

                task = self.find_scheduled_task(req, tsi, start_datetime,
                                                end_datetime)

            task_class = task_class_lookup[tsi.task_table_name]

            task_list.append(
                ScheduledTaskInfo(
                    task_class.shortname,
                    tsi.task_table_name,
                    is_anonymous=task_class.is_anonymous,
                    task=task,
                    start_datetime=start_datetime,
                    end_datetime=end_datetime,
                ))

        return task_list