def deactivate_project(requested_by_user: int, project_id: int) -> bool:
        """
        Deactivates an active project

        :param requested_by_user:   ID of the user that requested modification of the user
        :param project_id: ID of the project that should be deactivated

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Start a new revision
            revision_id = None

            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection,
                    datetime.datetime.utcnow(),
                    requested_by_user)

                if revision_id is None:
                    success = False

            # Read project
            project = None

            if success:
                project = ProjectManagementInterface.__read_project_by_id(connection,
                                                                          project_id,
                                                                          revision_id)

                if project is None:
                    success = False
                elif not project["active"]:
                    # Error, project is already inactive
                    success = False

            # Deactivate project
            if success:
                success = DatabaseInterface.tables().project_information.insert_row(
                    connection,
                    project_id,
                    project["short_name"],
                    project["full_name"],
                    project["description"],
                    False,
                    revision_id)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
def _initialize_system():
    # Authentication
    AuthenticationInterface.remove_all_authentication_methods()
    AuthenticationInterface.add_authentication_method(AuthenticationMethodBasic())

    # Database
    DatabaseInterface.load_database_plugin(DatabaseSqlite("database.db"))
    def read_all_tracker_field_ids(tracker_id: int,
                                   tracker_field_selection=TrackerFieldSelection.Active,
                                   max_revision_id=None) -> List[int]:
        """
        Reads all tracker field IDs from the database

        :param tracker_id:              ID of the tracker
        :param tracker_field_selection: Search for active, inactive or all tracker
        :param max_revision_id:         Maximum revision ID for the search ("None" for latest
                                        revision)

        :return:    List of tracker field IDs
        """
        connection = DatabaseInterface.create_connection()
        
        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)
        
        # Reads all tracker field IDs from the database
        tracker_fields = None
        
        if max_revision_id is not None:
            tracker_fields = \
                DatabaseInterface.tables().tracker_field_information.read_all_tracker_field_ids(
                    connection,
                    tracker_id,
                    tracker_field_selection,
                    max_revision_id)
        
        return tracker_fields
    def read_tracker_by_id(tracker_id: int, max_revision_id=None) -> Optional[dict]:
        """
        Reads a tracker (active or inactive) that matches the specified tracker ID

        :param tracker_id:      ID of the tracker
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker information object

        Returned dictionary contains items:

        - id
        - project_id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()
        
        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)
        
        # Read a tracker that matches the specified tracker ID
        tracker = None
        
        if max_revision_id is not None:
            tracker = TrackerManagementInterface.__read_tracker_by_id(connection,
                                                                      tracker_id,
                                                                      max_revision_id)
        
        return tracker
    def read_all_tracker_ids(project_id: int,
                             tracker_selection=TrackerSelection.Active,
                             max_revision_id=None) -> List[int]:
        """
        Reads all tracker IDs from the database

        :param project_id:          ID of the project
        :param tracker_selection:   Search for active, inactive or all tracker
        :param max_revision_id:     Maximum revision ID for the search ("None" for latest revision)

        :return:    List of tracker IDs
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Reads all tracker IDs from the database
        trackers = None

        if max_revision_id is not None:
            trackers = DatabaseInterface.tables(
            ).tracker_information.read_all_tracker_ids(connection, project_id,
                                                       tracker_selection,
                                                       max_revision_id)

        return trackers
    def read_tracker_by_id(tracker_id: int,
                           max_revision_id=None) -> Optional[dict]:
        """
        Reads a tracker (active or inactive) that matches the specified tracker ID

        :param tracker_id:      ID of the tracker
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker information object

        Returned dictionary contains items:

        - id
        - project_id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Read a tracker that matches the specified tracker ID
        tracker = None

        if max_revision_id is not None:
            tracker = TrackerManagementInterface.__read_tracker_by_id(
                connection, tracker_id, max_revision_id)

        return tracker
    def read_project_by_id(project_id: int,
                           max_revision_id=None) -> Optional[dict]:
        """
        Reads a project (active or inactive) that matches the specified project ID

        :param project_id:      ID of the project
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Project information object

        Returned dictionary contains items:

        - id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Read a project that matches the specified project ID
        project = None

        if max_revision_id is not None:
            project = ProjectManagementInterface.__read_project_by_id(
                connection, project_id, max_revision_id)

        return project
    def activate_tracker(requested_by_user: int, tracker_id: int) -> bool:
        """
        Activates an inactive tracker

        :param requested_by_user:   ID of the user that requested modification of the user
        :param tracker_id:          ID of the tracker that should be activated

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()
        
        try:
            success = connection.begin_transaction()
            
            # Start a new revision
            revision_id = None
            
            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection,
                    datetime.datetime.utcnow(),
                    requested_by_user)
                
                if revision_id is None:
                    success = False
            
            # Read tracker
            tracker = None
            
            if success:
                tracker = TrackerManagementInterface.__read_tracker_by_id(connection,
                                                                          tracker_id,
                                                                          revision_id)
                
                if tracker is None:
                    success = False
                elif tracker["active"]:
                    # Error, tracker is already active
                    success = False
            
            # Activate tracker
            if success:
                success = DatabaseInterface.tables().tracker_information.insert_row(
                    connection,
                    tracker_id,
                    tracker["short_name"],
                    tracker["full_name"],
                    tracker["description"],
                    True,
                    revision_id)
            
            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise
        
        return success
    def read_all_project_ids(project_selection=ProjectSelection.Active,
                             max_revision_id=None) -> List[int]:
        """
        Reads all project IDs from the database

        :param project_selection:   Search for active, inactive or all project
        :param max_revision_id:     Maximum revision ID for the search ("None" for latest revision)

        :return:    List of project IDs
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)

        # Reads all project IDs from the database
        projects = None

        if max_revision_id is not None:
            projects = DatabaseInterface.tables().project_information.read_all_project_ids(
                connection,
                project_selection,
                max_revision_id)

        return projects
    def read_project_by_id(project_id: int, max_revision_id=None) -> Optional[dict]:
        """
        Reads a project (active or inactive) that matches the specified project ID

        :param project_id:      ID of the project
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Project information object

        Returned dictionary contains items:

        - id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)

        # Read a project that matches the specified project ID
        project = None

        if max_revision_id is not None:
            project = ProjectManagementInterface.__read_project_by_id(connection,
                                                                      project_id,
                                                                      max_revision_id)

        return project
    def read_all_project_ids(project_selection=ProjectSelection.Active,
                             max_revision_id=None) -> List[int]:
        """
        Reads all project IDs from the database

        :param project_selection:   Search for active, inactive or all project
        :param max_revision_id:     Maximum revision ID for the search ("None" for latest revision)

        :return:    List of project IDs
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Reads all project IDs from the database
        projects = None

        if max_revision_id is not None:
            projects = DatabaseInterface.tables(
            ).project_information.read_all_project_ids(connection,
                                                       project_selection,
                                                       max_revision_id)

        return projects
def _initialize_system():
    # Authentication
    AuthenticationInterface.remove_all_authentication_methods()
    AuthenticationInterface.add_authentication_method(
        AuthenticationMethodBasic())

    # Database
    DatabaseInterface.load_database_plugin(DatabaseSqlite("database.db"))
    def update_user_information(user_to_modify: int,
                                user_name: str,
                                display_name: str,
                                email: str,
                                active: bool) -> bool:
        """
        Updates user's information

        :param user_to_modify:  ID of the user that should be modified
        :param user_name:       User's new user name
        :param display_name:    User's new display name
        :param email:           User's new email address
        :param active:          User's new state (active or inactive)

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Check if there is already an existing user with the same user name
            if success:
                user = UserManagementInterface.__read_user_by_user_name(connection, user_name)

                if user is not None:
                    if user["id"] != user_to_modify:
                        success = False

            # Check if there is already an existing user with the same display name
            if success:
                user = UserManagementInterface.__read_user_by_display_name(connection,
                                                                           display_name)

                if user is not None:
                    if user["id"] != user_to_modify:
                        success = False

            # Update user's information
            if success:
                success = DatabaseInterface.tables().user.update_row(connection,
                                                                     user_to_modify,
                                                                     user_name,
                                                                     display_name,
                                                                     email,
                                                                     active)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
Esempio n. 14
0
    def deactivate_tracker_field(requested_by_user: int,
                                 tracker_field_id: int) -> bool:
        """
        Deactivates an active tracker field

        :param requested_by_user:   ID of the user that requested modification of the user
        :param tracker_field_id:    ID of the tracker field that should be deactivated

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Start a new revision
            revision_id = None

            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection, datetime.datetime.utcnow(), requested_by_user)

                if revision_id is None:
                    success = False

            # Read tracker field
            tracker_field = None

            if success:
                tracker_field = TrackerFieldManagementInterface.__read_tracker_field_by_id(
                    connection, tracker_field_id, revision_id)

                if tracker_field is None:
                    success = False
                elif not tracker_field["active"]:
                    # Error, tracker field is already inactive
                    success = False

            # Deactivate tracker field
            if success:
                success = DatabaseInterface.tables(
                ).tracker_field_information.insert_row(
                    connection, tracker_field_id, tracker_field["name"],
                    tracker_field["display_name"],
                    tracker_field["description"], tracker_field["field_type"],
                    tracker_field["required"], False, revision_id)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
Esempio n. 15
0
    def __create_tracker_field(connection: Connection, tracker_id: int,
                               name: str, display_name: str, description: str,
                               field_type: str, required: bool,
                               revision_id: int) -> Optional[int]:
        """
        Creates a new tracker field

        :param connection:      Database connection
        :param tracker_id:      ID of the tracker
        :param name:            Tracker field's name
        :param display_name:    Tracker field's display name
        :param description:     Tracker field's description
        :param field_type:      Tracker field's type
        :param required:        Necessity of the tracker field (required or not)
        :param revision_id:     Revision ID

        :return:    Tracker field ID of the newly created tracker field
        """
        # Check if a tracker field with the same name already exists
        tracker_field = TrackerFieldManagementInterface.__read_tracker_field_by_name(
            connection, name, revision_id)

        if tracker_field is not None:
            return None

        # Check if a tracker field with the same display name already exists
        tracker_field = TrackerFieldManagementInterface.__read_tracker_field_by_display_name(
            connection, display_name, revision_id)

        if tracker_field is not None:
            return None

        # Create the tracker field in the new revision
        tracker_field_id = DatabaseInterface.tables().tracker_field.insert_row(
            connection, tracker_id)

        if tracker_field_id is None:
            return None

        # Add tracker field information to the tracker field
        tracker_field_information_id = \
            DatabaseInterface.tables().tracker_field_information.insert_row(
                connection,
                tracker_field_id,
                name,
                display_name,
                description,
                field_type,
                required,
                True,
                revision_id)

        if tracker_field_information_id is None:
            return None

        return tracker_field_id
    def read_all_user_ids(user_selection=UserSelection.Active) -> List[int]:
        """
        Reads all user IDs from the database

        :param user_selection:  Search for active, inactive or all users

        :return:    List of user IDs
        """
        connection = DatabaseInterface.create_connection()
        return DatabaseInterface.tables().user.read_all_ids(connection, user_selection)
    def deactivate_project(requested_by_user: int, project_id: int) -> bool:
        """
        Deactivates an active project

        :param requested_by_user:   ID of the user that requested modification of the user
        :param project_id: ID of the project that should be deactivated

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Start a new revision
            revision_id = None

            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection, datetime.datetime.utcnow(), requested_by_user)

                if revision_id is None:
                    success = False

            # Read project
            project = None

            if success:
                project = ProjectManagementInterface.__read_project_by_id(
                    connection, project_id, revision_id)

                if project is None:
                    success = False
                elif not project["active"]:
                    # Error, project is already inactive
                    success = False

            # Deactivate project
            if success:
                success = DatabaseInterface.tables(
                ).project_information.insert_row(connection, project_id,
                                                 project["short_name"],
                                                 project["full_name"],
                                                 project["description"], False,
                                                 revision_id)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
Esempio n. 18
0
    def create_tracker_fields(requested_by_user: int, tracker_id: int,
                              fields: List[dict]) -> bool:
        """
        Creates a new tracker

        :param requested_by_user:   ID of the user that requested creation of the new tracker field
        :param tracker_id:          ID of the tracker
        :param fields:              Tracker fields

        :return:    Success or failure

        Fields parameter needs to contain a list of dictionaries with the following items:

        - name:         Tracker field's name
        - display_name: Tracker field's display name
        - description:  Tracker field's description
        - field_type:   Tracker field's type
        - required:     Necessity of the tracker field (required or not)
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Start a new revision
            revision_id = None

            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection, datetime.datetime.utcnow(), requested_by_user)

                if revision_id is None:
                    success = False

            # Create the tracker
            if success:
                for field in fields:
                    tracker_field_id = TrackerFieldManagementInterface.__create_tracker_field(
                        connection, tracker_id, field["name"],
                        field["display_name"], field["description"],
                        field["field_type"], field["required"], revision_id)

                    if tracker_field_id is None:
                        success = False
                        break

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
    def activate_tracker(requested_by_user: int, tracker_id: int) -> bool:
        """
        Activates an inactive tracker

        :param requested_by_user:   ID of the user that requested modification of the user
        :param tracker_id:          ID of the tracker that should be activated

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Start a new revision
            revision_id = None

            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection, datetime.datetime.utcnow(), requested_by_user)

                if revision_id is None:
                    success = False

            # Read tracker
            tracker = None

            if success:
                tracker = TrackerManagementInterface.__read_tracker_by_id(
                    connection, tracker_id, revision_id)

                if tracker is None:
                    success = False
                elif tracker["active"]:
                    # Error, tracker is already active
                    success = False

            # Activate tracker
            if success:
                success = DatabaseInterface.tables(
                ).tracker_information.insert_row(connection, tracker_id,
                                                 tracker["short_name"],
                                                 tracker["full_name"],
                                                 tracker["description"], True,
                                                 revision_id)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
    def create_tracker(requested_by_user: int,
                       project_id: int,
                       short_name: str,
                       full_name: str,
                       description: str) -> Optional[int]:
        """
        Creates a new tracker

        :param requested_by_user:   ID of the user that requested creation of the new tracker
        :param project_id:          ID of the project
        :param short_name:          Tracker's short name
        :param full_name:           Tracker's full name
        :param description:         Tracker's description

        :return:    Tracker ID of the new tracker
        """
        tracker_id = None
        connection = DatabaseInterface.create_connection()
        
        try:
            success = connection.begin_transaction()
            
            # Start a new revision
            revision_id = None
            
            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection,
                    datetime.datetime.utcnow(),
                    requested_by_user)
                
                if revision_id is None:
                    success = False
            
            # Create the tracker
            if success:
                tracker_id = TrackerManagementInterface.__create_tracker(connection,
                                                                         project_id,
                                                                         short_name,
                                                                         full_name,
                                                                         description,
                                                                         revision_id)
                
                if tracker_id is None:
                    success = False
            
            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise
        
        return tracker_id
    def setUp(self):
        # Authentication
        AuthenticationInterface.remove_all_authentication_methods()
        AuthenticationInterface.add_authentication_method(AuthenticationMethodBasic())

        # Database
        DatabaseInterface.load_database_plugin(DatabaseSqlite("database.db"))
        DatabaseInterface.create_new_database()

        # Data members
        self.__admin_user_id = 1
    def __create_tracker(connection: Connection,
                         project_id: int,
                         short_name: str,
                         full_name: str,
                         description: str,
                         revision_id: int) -> Optional[int]:
        """
        Creates a new tracker

        :param connection:  Database connection
        :param project_id:  ID of the project
        :param short_name:  Tracker's short name
        :param full_name:   Tracker's full name
        :param description: Tracker's description
        :param revision_id: Revision ID

        :return:    Tracker ID of the newly created tracker
        """
        # Check if a tracker with the same short name already exists
        tracker = TrackerManagementInterface.__read_tracker_by_short_name(connection,
                                                                          short_name,
                                                                          revision_id)
        
        if tracker is not None:
            return None
        
        # Check if a tracker with the same full name already exists
        tracker = TrackerManagementInterface.__read_tracker_by_full_name(connection,
                                                                         full_name,
                                                                         revision_id)
        
        if tracker is not None:
            return None
        
        # Create the tracker in the new revision
        tracker_id = DatabaseInterface.tables().tracker.insert_row(connection, project_id)
        
        if tracker_id is None:
            return None
        
        # Add tracker information to the tracker
        tracker_information_id = DatabaseInterface.tables().tracker_information.insert_row(
            connection,
            tracker_id,
            short_name,
            full_name,
            description,
            True,
            revision_id)
        
        if tracker_information_id is None:
            return None
        
        return tracker_id
    def read_all_user_ids(user_selection=UserSelection.Active) -> List[int]:
        """
        Reads all user IDs from the database

        :param user_selection:  Search for active, inactive or all users

        :return:    List of user IDs
        """
        connection = DatabaseInterface.create_connection()
        return DatabaseInterface.tables().user.read_all_ids(
            connection, user_selection)
    def setUp(self):
        # Authentication
        AuthenticationInterface.remove_all_authentication_methods()
        AuthenticationInterface.add_authentication_method(
            AuthenticationMethodBasic())

        # Database
        DatabaseInterface.load_database_plugin(DatabaseSqlite("database.db"))
        DatabaseInterface.create_new_database()

        # Data members
        self.__admin_user_id = 1
    def update_user_information(user_to_modify: int, user_name: str,
                                display_name: str, email: str,
                                active: bool) -> bool:
        """
        Updates user's information

        :param user_to_modify:  ID of the user that should be modified
        :param user_name:       User's new user name
        :param display_name:    User's new display name
        :param email:           User's new email address
        :param active:          User's new state (active or inactive)

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Check if there is already an existing user with the same user name
            if success:
                user = UserManagementInterface.__read_user_by_user_name(
                    connection, user_name)

                if user is not None:
                    if user["id"] != user_to_modify:
                        success = False

            # Check if there is already an existing user with the same display name
            if success:
                user = UserManagementInterface.__read_user_by_display_name(
                    connection, display_name)

                if user is not None:
                    if user["id"] != user_to_modify:
                        success = False

            # Update user's information
            if success:
                success = DatabaseInterface.tables().user.update_row(
                    connection, user_to_modify, user_name, display_name, email,
                    active)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
    def __create_project(connection: Connection,
                         short_name: str,
                         full_name: str,
                         description: str,
                         revision_id: int) -> Optional[int]:
        """
        Creates a new project

        :param connection:  Database connection
        :param short_name:  Project's short name
        :param full_name:   Project's full name
        :param description: Project's description
        :param revision_id: Revision ID

        :return:    Project ID of the newly created project
        """
        # Check if a project with the same short name already exists
        project = ProjectManagementInterface.__read_project_by_short_name(connection,
                                                                          short_name,
                                                                          revision_id)

        if project is not None:
            return None

        # Check if a project with the same full name already exists
        project = ProjectManagementInterface.__read_project_by_full_name(connection,
                                                                         full_name,
                                                                         revision_id)

        if project is not None:
            return None

        # Create the project in the new revision
        project_id = DatabaseInterface.tables().project.insert_row(connection)

        if project_id is None:
            return None

        # Add project information to the project
        project_information_id = DatabaseInterface.tables().project_information.insert_row(
            connection,
            project_id,
            short_name,
            full_name,
            description,
            True,
            revision_id)

        if project_information_id is None:
            return None

        return project_id
Esempio n. 27
0
    def create_tracker_field(requested_by_user: int, tracker_id: int,
                             name: str, display_name: str, description: str,
                             field_type: str, required: bool) -> Optional[int]:
        """
        Creates a new tracker

        :param requested_by_user:   ID of the user that requested creation of the new tracker field
        :param tracker_id:          ID of the tracker
        :param name:                Tracker field's name
        :param display_name:        Tracker field's display name
        :param description:         Tracker field's description
        :param field_type:          Tracker field's type
        :param required:            Necessity of the tracker field (required or not)

        :return:    Tracker field ID of the new tracker field
        """
        tracker_field_id = None
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Start a new revision
            revision_id = None

            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection, datetime.datetime.utcnow(), requested_by_user)

                if revision_id is None:
                    success = False

            # Create the tracker
            if success:
                tracker_field_id = TrackerFieldManagementInterface.__create_tracker_field(
                    connection, tracker_id, name, display_name, description,
                    field_type, required, revision_id)

                if tracker_field_id is None:
                    success = False

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return tracker_field_id
Esempio n. 28
0
    def read_tracker_fields_by_display_name(display_name: str,
                                            max_revision_id=None
                                            ) -> List[dict]:
        """
        Reads all active and inactive tracker fields that match the specified display name

        :param display_name:    Tracker field's display name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker field information of all tracker fields that match the search attribute

        Each dictionary in the returned list contains items:

        - id
        - tracker_id
        - name
        - display_name
        - description
        - field_type
        - required
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Read tracker fields that match the specified display name
        tracker_fields = list()

        if max_revision_id is not None:
            tracker_field_information_list = \
                DatabaseInterface.tables().tracker_field_information.read_information(
                    connection,
                    "display_name",
                    display_name,
                    TrackerFieldSelection.All,
                    max_revision_id)

            for tracker_field_information in tracker_field_information_list:
                tracker_fields.append(
                    TrackerFieldManagementInterface.
                    __parse_tracker_field_information(
                        tracker_field_information))

        return tracker_fields
    def create_tracker(requested_by_user: int, project_id: int,
                       short_name: str, full_name: str,
                       description: str) -> Optional[int]:
        """
        Creates a new tracker

        :param requested_by_user:   ID of the user that requested creation of the new tracker
        :param project_id:          ID of the project
        :param short_name:          Tracker's short name
        :param full_name:           Tracker's full name
        :param description:         Tracker's description

        :return:    Tracker ID of the new tracker
        """
        tracker_id = None
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Start a new revision
            revision_id = None

            if success:
                revision_id = DatabaseInterface.tables().revision.insert_row(
                    connection, datetime.datetime.utcnow(), requested_by_user)

                if revision_id is None:
                    success = False

            # Create the tracker
            if success:
                tracker_id = TrackerManagementInterface.__create_tracker(
                    connection, project_id, short_name, full_name, description,
                    revision_id)

                if tracker_id is None:
                    success = False

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return tracker_id
Esempio n. 30
0
    def __read_user_by_display_name(token: str, display_name: str) -> dict:
        """
        Reads current user's information

        :param token:           Session token which contains the current user's information
        :param display_name:    Display name

        :return:    User information object

        Returned dictionary contains items:

        - id
        - user_name
        - display_name
        - email
        - active
        """
        user = None
        success = False
        error_code = None
        error_message = None

        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Extract session user
            if success:
                session_user = RestrictedResource._read_session_user(
                    connection, token)

                if session_user is None:
                    success = False
                    error_code = 400
                    error_message = "Invalid session token"

            # Read requested user
            if success:
                user = UserManagementInterface.read_user_by_display_name(
                    connection, display_name)

                if user is None:
                    success = False
                    error_code = 400
                    error_message = "Invalid user name"

            connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            abort(500, message="Internal error, please try again")

        # Return user
        if success:
            return jsonify(user)
        else:
            if (error_code is not None) and (error_message is not None):
                abort(error_code, message=error_message)
            else:
                abort(500, message="Internal error")
    def __read_user_by_display_name(connection: Connection,
                                    display_name: str) -> Optional[dict]:
        """
        Reads an active user that matches the specified display name

        :param display_name:    User's display name

        :return:    User information object

        Returned dictionary contains items:

        - id
        - user_name
        - display_name
        - email
        - active
        """
        # Read the users that match the search attribute
        users = DatabaseInterface.tables().user.read_users_by_attribute(
            connection, "display_name", display_name, UserSelection.Active)

        # Return a user only if exactly one was found
        user = None

        if users is not None:
            if len(users) == 1:
                user = users[0]

        return user
    def read_user_by_id(connection: Connection,
                        user_id: int) -> Optional[dict]:
        """
        Reads a user (active or inactive) that matches the specified user ID

        :param connection:  Database connection
        :param user_id:     ID of the user

        :return:    User information object

        Returned dictionary contains items:

        - id
        - user_name
        - display_name
        - email
        - active
        """
        # Read the users that match the search attribute
        users = DatabaseInterface.tables().user.read_users_by_attribute(
            connection, "id", user_id, UserSelection.All)

        # Return a user only if exactly one was found
        user = None

        if users is not None:
            if len(users) == 1:
                user = users[0]

        return user
    def read_user_by_id(connection: Connection, user_id: int) -> Optional[dict]:
        """
        Reads a user (active or inactive) that matches the specified user ID

        :param connection:  Database connection
        :param user_id:     ID of the user

        :return:    User information object

        Returned dictionary contains items:

        - id
        - user_name
        - display_name
        - email
        - active
        """
        # Read the users that match the search attribute
        users = DatabaseInterface.tables().user.read_users_by_attribute(connection,
                                                                        "id",
                                                                        user_id,
                                                                        UserSelection.All)

        # Return a user only if exactly one was found
        user = None

        if users is not None:
            if len(users) == 1:
                user = users[0]

        return user
    def __read_user_by_display_name(connection: Connection, display_name: str) -> Optional[dict]:
        """
        Reads an active user that matches the specified display name

        :param display_name:    User's display name

        :return:    User information object

        Returned dictionary contains items:

        - id
        - user_name
        - display_name
        - email
        - active
        """
        # Read the users that match the search attribute
        users = DatabaseInterface.tables().user.read_users_by_attribute(connection,
                                                                        "display_name",
                                                                        display_name,
                                                                        UserSelection.Active)

        # Return a user only if exactly one was found
        user = None

        if users is not None:
            if len(users) == 1:
                user = users[0]

        return user
    def create_session_token(connection: Connection,
                             user_id: int) -> Optional[str]:
        """
        Creates a session token

        :param connection:  Database connection
        :param user_id:     ID of the user

        :return:    Token value
        """
        # Generate a token
        token = None

        for i in range(10):
            # Generate a random UUID (up to 10 tries)
            random_uuid = uuid.uuid4()

            # Check if this token already exists in the database
            existing_session_token = UserManagementInterface.read_session_token(
                connection, random_uuid.hex)

            if existing_session_token is None:
                token = random_uuid.hex
                break

        # Store the token in the database
        if token is not None:
            row_id = DatabaseInterface.tables().session_token.insert_row(
                connection, user_id, datetime.datetime.utcnow(), token)

            # In case of an error invalidate the generated token
            if row_id is None:
                token = None

        return token
    def __create_tracker(connection: Connection, project_id: int,
                         short_name: str, full_name: str, description: str,
                         revision_id: int) -> Optional[int]:
        """
        Creates a new tracker

        :param connection:  Database connection
        :param project_id:  ID of the project
        :param short_name:  Tracker's short name
        :param full_name:   Tracker's full name
        :param description: Tracker's description
        :param revision_id: Revision ID

        :return:    Tracker ID of the newly created tracker
        """
        # Check if a tracker with the same short name already exists
        tracker = TrackerManagementInterface.__read_tracker_by_short_name(
            connection, short_name, revision_id)

        if tracker is not None:
            return None

        # Check if a tracker with the same full name already exists
        tracker = TrackerManagementInterface.__read_tracker_by_full_name(
            connection, full_name, revision_id)

        if tracker is not None:
            return None

        # Create the tracker in the new revision
        tracker_id = DatabaseInterface.tables().tracker.insert_row(
            connection, project_id)

        if tracker_id is None:
            return None

        # Add tracker information to the tracker
        tracker_information_id = DatabaseInterface.tables(
        ).tracker_information.insert_row(connection, tracker_id, short_name,
                                         full_name, description, True,
                                         revision_id)

        if tracker_information_id is None:
            return None

        return tracker_id
    def read_tracker_fields_by_display_name(display_name: str,
                                            max_revision_id=None) -> List[dict]:
        """
        Reads all active and inactive tracker fields that match the specified display name

        :param display_name:    Tracker field's display name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker field information of all tracker fields that match the search attribute

        Each dictionary in the returned list contains items:

        - id
        - tracker_id
        - name
        - display_name
        - description
        - field_type
        - required
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()
        
        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)
        
        # Read tracker fields that match the specified display name
        tracker_fields = list()
        
        if max_revision_id is not None:
            tracker_field_information_list = \
                DatabaseInterface.tables().tracker_field_information.read_information(
                    connection,
                    "display_name",
                    display_name,
                    TrackerFieldSelection.All,
                    max_revision_id)
            
            for tracker_field_information in tracker_field_information_list:
                tracker_fields.append(
                    TrackerFieldManagementInterface.__parse_tracker_field_information(
                        tracker_field_information))
        
        return tracker_fields
Esempio n. 38
0
    def __read_user_by_display_name(token: str, display_name: str) -> dict:
        """
        Reads current user's information

        :param token:           Session token which contains the current user's information
        :param display_name:    Display name

        :return:    User information object

        Returned dictionary contains items:

        - id
        - user_name
        - display_name
        - email
        - active
        """
        user = None
        success = False
        error_code = None
        error_message = None

        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Extract session user
            if success:
                session_user = RestrictedResource._read_session_user(connection, token)

                if session_user is None:
                    success = False
                    error_code = 400
                    error_message = "Invalid session token"

            # Read requested user
            if success:
                user = UserManagementInterface.read_user_by_display_name(connection, display_name)

                if user is None:
                    success = False
                    error_code = 400
                    error_message = "Invalid user name"

            connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            abort(500, message="Internal error, please try again")

        # Return user
        if success:
            return jsonify(user)
        else:
            if (error_code is not None) and (error_message is not None):
                abort(error_code, message=error_message)
            else:
                abort(500, message="Internal error")
    def read_trackers_by_full_name(full_name: str,
                                   max_revision_id=None) -> List[dict]:
        """
        Reads all active and inactive trackers that match the specified full name

        :param full_name:       Tracker's full name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker information of all trackers that match the search attribute

        Each dictionary in the returned list contains items:

        - id
        - project_id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Read trackers that match the specified full name
        trackers = list()

        if max_revision_id is not None:
            tracker_information_list = \
                DatabaseInterface.tables().tracker_information.read_information(
                    connection,
                    "full_name",
                    full_name,
                    TrackerSelection.All,
                    max_revision_id)

            for tracker_information in tracker_information_list:
                trackers.append(
                    TrackerManagementInterface.__parse_tracker_information(
                        tracker_information))

        return trackers
    def __create_project(connection: Connection, short_name: str,
                         full_name: str, description: str,
                         revision_id: int) -> Optional[int]:
        """
        Creates a new project

        :param connection:  Database connection
        :param short_name:  Project's short name
        :param full_name:   Project's full name
        :param description: Project's description
        :param revision_id: Revision ID

        :return:    Project ID of the newly created project
        """
        # Check if a project with the same short name already exists
        project = ProjectManagementInterface.__read_project_by_short_name(
            connection, short_name, revision_id)

        if project is not None:
            return None

        # Check if a project with the same full name already exists
        project = ProjectManagementInterface.__read_project_by_full_name(
            connection, full_name, revision_id)

        if project is not None:
            return None

        # Create the project in the new revision
        project_id = DatabaseInterface.tables().project.insert_row(connection)

        if project_id is None:
            return None

        # Add project information to the project
        project_information_id = DatabaseInterface.tables(
        ).project_information.insert_row(connection, project_id, short_name,
                                         full_name, description, True,
                                         revision_id)

        if project_information_id is None:
            return None

        return project_id
    def read_trackers_by_full_name(full_name: str,
                                   max_revision_id=None) -> List[dict]:
        """
        Reads all active and inactive trackers that match the specified full name

        :param full_name:       Tracker's full name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker information of all trackers that match the search attribute

        Each dictionary in the returned list contains items:

        - id
        - project_id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()
        
        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)
        
        # Read trackers that match the specified full name
        trackers = list()
        
        if max_revision_id is not None:
            tracker_information_list = \
                DatabaseInterface.tables().tracker_information.read_information(
                    connection,
                    "full_name",
                    full_name,
                    TrackerSelection.All,
                    max_revision_id)
            
            for tracker_information in tracker_information_list:
                trackers.append(TrackerManagementInterface.__parse_tracker_information(
                    tracker_information))
        
        return trackers
    def deactivate_user(user_id: int) -> bool:
        """
        Deactivates an active user

        :param user_id: ID of the user that should be deactivated

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Read user
            user = None

            if success:
                user = UserManagementInterface.read_user_by_id(connection, user_id)

                if user is None:
                    success = False
                elif not user["active"]:
                    # Error, user is already inactive
                    success = False

            # Deactivate user
            if success:
                success = DatabaseInterface.tables().user.update_row(connection,
                                                                     user_id,
                                                                     user["user_name"],
                                                                     user["display_name"],
                                                                     user["email"],
                                                                     False)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
    def read_projects_by_short_name(short_name: str,
                                    max_revision_id=None) -> List[dict]:
        """
        Reads all active and inactive projects that match the specified short name

        :param short_name:      Project's short name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Project information of all projects that match the search attribute

        Each dictionary in the returned list contains items:

        - id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Read projects that match the specified short name
        projects = list()

        if max_revision_id is not None:
            project_information_list = \
                DatabaseInterface.tables().project_information.read_information(
                    connection,
                    "short_name",
                    short_name,
                    ProjectSelection.All,
                    max_revision_id)

            for project_information in project_information_list:
                projects.append(
                    ProjectManagementInterface.__parse_project_information(
                        project_information))

        return projects
    def delete_session_token(connection: Connection, token: str) -> bool:
        """
        Deletes the specified session token

        :param connection:  Database connection
        :param token:       Session's token value

        :return:    Success or failure
        """
        # Check if the specified token is valid
        existing_session_token = UserManagementInterface.read_session_token(connection, token)

        if existing_session_token is None:
            # Error, invalid token
            return False

        # Delete the token from the database
        DatabaseInterface.tables().session_token.delete_row_by_token(connection, token)
        return True
    def read_projects_by_short_name(short_name: str, max_revision_id=None) -> List[dict]:
        """
        Reads all active and inactive projects that match the specified short name

        :param short_name:      Project's short name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Project information of all projects that match the search attribute

        Each dictionary in the returned list contains items:

        - id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)

        # Read projects that match the specified short name
        projects = list()

        if max_revision_id is not None:
            project_information_list = \
                DatabaseInterface.tables().project_information.read_information(
                    connection,
                    "short_name",
                    short_name,
                    ProjectSelection.All,
                    max_revision_id)

            for project_information in project_information_list:
                projects.append(ProjectManagementInterface.__parse_project_information(
                    project_information))

        return projects
    def deactivate_user(user_id: int) -> bool:
        """
        Deactivates an active user

        :param user_id: ID of the user that should be deactivated

        :return:    Success or failure
        """
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Read user
            user = None

            if success:
                user = UserManagementInterface.read_user_by_id(
                    connection, user_id)

                if user is None:
                    success = False
                elif not user["active"]:
                    # Error, user is already inactive
                    success = False

            # Deactivate user
            if success:
                success = DatabaseInterface.tables().user.update_row(
                    connection, user_id, user["user_name"],
                    user["display_name"], user["email"], False)

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return success
    def delete_session_token(connection: Connection, token: str) -> bool:
        """
        Deletes the specified session token

        :param connection:  Database connection
        :param token:       Session's token value

        :return:    Success or failure
        """
        # Check if the specified token is valid
        existing_session_token = UserManagementInterface.read_session_token(
            connection, token)

        if existing_session_token is None:
            # Error, invalid token
            return False

        # Delete the token from the database
        DatabaseInterface.tables().session_token.delete_row_by_token(
            connection, token)
        return True
Esempio n. 48
0
    def post(self):
        """
        Logs out the user
        """
        # Extract session token from the request
        token = self._read_session_token()

        # Log out
        success = False
        error_code = None
        error_message = None

        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Get the session token
            session_token = None

            if success:
                session_token = UserManagementInterface.read_session_token(connection, token)

                if session_token is None:
                    success = False
                    error_code = 400
                    error_message = "Invalid session token"

            # Delete session token
            if success:
                success = UserManagementInterface.delete_session_token(connection, token)

                if not success:
                    error_code = 500
                    error_message = "Failed to log out, please try again"

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            abort(500, message="Internal error, please try again")

        # Return response
        if success:
            return None
        else:
            if (error_code is not None) and (error_message is not None):
                abort(error_code, message=error_message)
            else:
                abort(500, message="Internal error")
    def __read_user_authentication(connection: Connection,
                                   user_id: int) -> Optional[dict]:
        """
        Reads user's authentication

        :param connection:  Database connection
        :param user_id:     ID of the user

        :return:    User authentication object

        Returned dictionary contains items:

        - authentication_type
        - authentication_parameters
        """
        # Read the user's authentication
        user_authentication = DatabaseInterface.tables(
        ).user_authentication.read_authentication(connection, user_id)

        if user_authentication is None:
            return None

        # Read the user's authentication parameters
        authentication_parameters = \
            DatabaseInterface.tables().user_authentication_parameter.read_authentication_parameters(
                connection,
                user_id)

        if authentication_parameters is None:
            return None

        # Create authentication object
        authentication_object = dict()
        authentication_object["authentication_type"] = user_authentication[
            "authentication_type"]
        authentication_object[
            "authentication_parameters"] = authentication_parameters

        return authentication_object
    def read_tracker_field_by_display_name(display_name: str,
                                           max_revision_id=None) -> Optional[dict]:
        """
        Reads an active tracker field that matches the specified display name

        :param display_name:    Tracker field's display name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker field information object

        Returned dictionary contains items:

        - id
        - tracker_id
        - name
        - display_name
        - description
        - field_type
        - required
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()
        
        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables().revision.read_current_revision_id(
                connection)
        
        # Read a tracker field that matches the specified display name
        tracker_field = None
        
        if max_revision_id is not None:
            tracker_field = TrackerFieldManagementInterface.__read_tracker_field_by_display_name(
                connection,
                display_name,
                max_revision_id)
        
        return tracker_field
Esempio n. 51
0
    def __read_tracker_field_by_id(connection: Connection,
                                   tracker_field_id: int,
                                   max_revision_id: int) -> Optional[dict]:
        """
        Reads a tracker field (active or inactive) that matches the search parameters

        :param connection:          Database connection
        :param tracker_field_id:    ID of the tracker
        :param max_revision_id:     Maximum revision ID for the search

        :return:    Tracker field information object

        Returned dictionary contains items:

        - id
        - tracker_id
        - name
        - display_name
        - description
        - field_type
        - required
        - active
        - revision_id
        """
        # Read the tracker fields that match the search attribute
        tracker_fields = DatabaseInterface.tables(
        ).tracker_field_information.read_information(connection,
                                                     "tracker_field_id",
                                                     tracker_field_id,
                                                     TrackerFieldSelection.All,
                                                     max_revision_id)

        # Return a tracker field only if exactly one was found
        tracker_field = None

        if tracker_fields is not None:
            if len(tracker_fields) == 1:
                tracker_field = {
                    "id": tracker_fields[0]["tracker_field_id"],
                    "tracker_id": tracker_fields[0]["tracker_id"],
                    "name": tracker_fields[0]["name"],
                    "display_name": tracker_fields[0]["display_name"],
                    "description": tracker_fields[0]["description"],
                    "field_type": tracker_fields[0]["field_type"],
                    "required": tracker_fields[0]["required"],
                    "active": tracker_fields[0]["active"],
                    "revision_id": tracker_fields[0]["revision_id"]
                }

        return tracker_field
Esempio n. 52
0
    def read_tracker_field_by_display_name(display_name: str,
                                           max_revision_id=None
                                           ) -> Optional[dict]:
        """
        Reads an active tracker field that matches the specified display name

        :param display_name:    Tracker field's display name
        :param max_revision_id: Maximum revision ID for the search ("None" for latest revision)

        :return:    Tracker field information object

        Returned dictionary contains items:

        - id
        - tracker_id
        - name
        - display_name
        - description
        - field_type
        - required
        - active
        - revision_id
        """
        connection = DatabaseInterface.create_connection()

        if max_revision_id is None:
            max_revision_id = DatabaseInterface.tables(
            ).revision.read_current_revision_id(connection)

        # Read a tracker field that matches the specified display name
        tracker_field = None

        if max_revision_id is not None:
            tracker_field = TrackerFieldManagementInterface.__read_tracker_field_by_display_name(
                connection, display_name, max_revision_id)

        return tracker_field
    def __read_user_authentication(connection: Connection, user_id: int) -> Optional[dict]:
        """
        Reads user's authentication

        :param connection:  Database connection
        :param user_id:     ID of the user

        :return:    User authentication object

        Returned dictionary contains items:

        - authentication_type
        - authentication_parameters
        """
        # Read the user's authentication
        user_authentication = DatabaseInterface.tables().user_authentication.read_authentication(
            connection,
            user_id)

        if user_authentication is None:
            return None

        # Read the user's authentication parameters
        authentication_parameters = \
            DatabaseInterface.tables().user_authentication_parameter.read_authentication_parameters(
                connection,
                user_id)

        if authentication_parameters is None:
            return None

        # Create authentication object
        authentication_object = dict()
        authentication_object["authentication_type"] = user_authentication["authentication_type"]
        authentication_object["authentication_parameters"] = authentication_parameters

        return authentication_object
    def __read_tracker_field_by_display_name(connection: Connection,
                                             display_name: str,
                                             max_revision_id: int) -> Optional[dict]:
        """
        Reads an active tracker that matches the specified full name

        :param connection:      Database connection
        :param display_name:    Tracker's display name
        :param max_revision_id: Maximum revision ID for the search

        :return:    Tracker field information object

        Returned dictionary contains items:

        - id
        - tracker_id
        - name
        - display_name
        - description
        - field_type
        - required
        - active
        - revision_id
        """
        # Read the tracker fields that match the search attribute
        tracker_fields = DatabaseInterface.tables().tracker_field_information.read_information(
            connection,
            "display_name",
            display_name,
            TrackerFieldSelection.Active,
            max_revision_id)

        # Return a tracker field only if exactly one was found
        tracker_field = None

        if tracker_fields is not None:
            if len(tracker_fields) == 1:
                tracker_field = {"id": tracker_fields[0]["tracker_field_id"],
                                 "tracker_id": tracker_fields[0]["tracker_id"],
                                 "name": tracker_fields[0]["name"],
                                 "display_name": tracker_fields[0]["display_name"],
                                 "description": tracker_fields[0]["description"],
                                 "field_type": tracker_fields[0]["field_type"],
                                 "required": tracker_fields[0]["required"],
                                 "active": tracker_fields[0]["active"],
                                 "revision_id": tracker_fields[0]["revision_id"]}

        return tracker_field
    def __read_tracker_by_full_name(connection: Connection,
                                    full_name: str,
                                    max_revision_id: int) -> Optional[dict]:
        """
        Reads an active tracker that matches the specified full name

        :param connection:      Database connection
        :param full_name:       Tracker's full name
        :param max_revision_id: Maximum revision ID for the search

        :return:    Tracker information object

        Returned dictionary contains items:

        - id
        - project_id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        # Read the trackers that match the search attribute
        trackers = DatabaseInterface.tables().tracker_information.read_information(
            connection,
            "full_name",
            full_name,
            TrackerSelection.Active,
            max_revision_id)
        
        # Return a tracker only if exactly one was found
        tracker = None
        
        if trackers is not None:
            if len(trackers) == 1:
                tracker = {"id": trackers[0]["tracker_id"],
                           "project_id": trackers[0]["project_id"],
                           "short_name": trackers[0]["short_name"],
                           "full_name": trackers[0]["full_name"],
                           "description": trackers[0]["description"],
                           "active": trackers[0]["active"],
                           "revision_id": trackers[0]["revision_id"]}
        
        return tracker
    def read_session_token(connection: Connection, token: str) -> Optional[dict]:
        """
        Reads a session token from the database

        :param connection:  Database connection
        :param token:       Session's token value

        :return:    Session token object

        Returned dictionary contains items:

        - id
        - user_id
        - created_on
        - token
        """
        session_token = DatabaseInterface.tables().session_token.read_token(connection, token)

        return session_token
    def create_user(user_name: str,
                    display_name: str,
                    email: str,
                    authentication_type: str,
                    authentication_parameters: dict) -> Optional[int]:
        """
        Creates a new user

        :param user_name:                   User's user name
        :param display_name:                User's display name
        :param email:                       Email address of the user
        :param authentication_type:         User's authentication type
        :param authentication_parameters:   User's authentication parameters

        :return:    User ID of the new user
        """
        user_id = None
        connection = DatabaseInterface.create_connection()

        try:
            success = connection.begin_transaction()

            # Create the user
            if success:
                user_id = UserManagementInterface.__create_user(connection,
                                                                user_name,
                                                                display_name,
                                                                email,
                                                                authentication_type,
                                                                authentication_parameters)

                if user_id is None:
                    success = False

            if success:
                connection.commit_transaction()
            else:
                connection.rollback_transaction()
        except:
            connection.rollback_transaction()
            raise

        return user_id
    def __read_project_by_full_name(connection: Connection,
                                    full_name: str,
                                    max_revision_id: int) -> Optional[dict]:
        """
        Reads an active project that matches the specified full name

        :param connection:      Database connection
        :param full_name:       Projects's full name
        :param max_revision_id: Maximum revision ID for the search

        :return:    Project information object

        Returned dictionary contains items:

        - id
        - short_name
        - full_name
        - description
        - active
        - revision_id
        """
        # Read the projects that match the search attribute
        projects = DatabaseInterface.tables().project_information.read_information(
            connection,
            "full_name",
            full_name,
            ProjectSelection.Active,
            max_revision_id)

        # Return a project only if exactly one was found
        project = None

        if projects is not None:
            if len(projects) == 1:
                project = {"id": projects[0]["project_id"],
                           "short_name": projects[0]["short_name"],
                           "full_name": projects[0]["full_name"],
                           "description": projects[0]["description"],
                           "active": projects[0]["active"],
                           "revision_id": projects[0]["revision_id"]}

        return project
    def read_users_by_display_name(connection: Connection, display_name: str) -> List[dict]:
        """
        Reads all active and inactive users that match the specified display name

        :param connection:      Database connection
        :param display_name:    User's display name

        :return:    User information of all users that match the search attribute

        Each dictionary in the returned list contains items:

        - id
        - user_name
        - display_name
        - email
        - active
        """
        return DatabaseInterface.tables().user.read_users_by_attribute(connection,
                                                                       "display_name",
                                                                       display_name,
                                                                       UserSelection.All)