Example #1
0
class Organisation(db.Model, BaseMixin, SerializerMixin):
    """
    Model to represent current organisation settings.
    """

    name = db.Column(db.String(80), unique=True, nullable=False)
    hours_by_day = db.Column(db.Integer(), default=8, nullable=False)
    has_avatar = db.Column(db.Boolean(), default=False)
    use_original_file_name = db.Column(db.Boolean(), default=False)
    timesheets_locked = db.Column(db.Boolean(), default=False)
    hd_by_default = db.Column(db.Boolean(), default=False)
    chat_token_slack = db.Column(db.String(80), default="")

    def present(self):
        return fields.serialize_dict(
            {
                "id": self.id,
                "chat_token_slack": self.chat_token_slack,
                "name": self.name,
                "has_avatar": self.has_avatar,
                "hours_by_day": self.hours_by_day,
                "hd_by_default": self.hd_by_default,
                "use_original_file_name": self.use_original_file_name,
                "timesheets_locked": self.timesheets_locked,
            }
        )
Example #2
0
class TaskStatus(db.Model, BaseMixin, SerializerMixin):
    """
    Describe the state of a task. A status marked as reviewable expects a
    preview file linked to relate comment.
    """
    name = db.Column(db.String(40), nullable=False)
    short_name = db.Column(db.String(10), unique=True, nullable=False)
    color = db.Column(db.String(7), nullable=False)
    is_reviewable = db.Column(db.Boolean(), default=False)
    is_done = db.Column(db.Boolean(), default=False)
    shotgun_id = db.Column(db.Integer)
Example #3
0
class Person(db.Model, BaseMixin, SerializerMixin):
    """
    Describe a member of the studio (and an API user).
    """
    first_name = db.Column(db.String(80), nullable=False)
    last_name = db.Column(db.String(80), nullable=False)
    email = db.Column(EmailType, unique=True)
    phone = db.Column(db.String(30))

    active = db.Column(db.Boolean(), default=True)
    last_presence = db.Column(db.Date())

    password = db.Column(db.Binary(60))
    desktop_login = db.Column(db.String(80))
    shotgun_id = db.Column(db.Integer, unique=True)
    timezone = db.Column(
        TimezoneType(backend="pytz"),
        default=pytz_timezone("Europe/Paris")
    )
    locale = db.Column(LocaleType, default=Locale("en", "US"))
    data = db.Column(JSONB)
    role = db.Column(db.String(30), default="user")
    has_avatar = db.Column(db.Boolean(), default=False)

    skills = db.relationship(
        "Department",
        secondary=department_link
    )

    def __repr__(self):
        if sys.version_info[0] < 3:
            return "<Person %s>" % self.full_name().encode("utf-8")
        else:
            return "<Person %s>" % self.full_name()

    def full_name(self):
        return "%s %s" % (
            self.first_name,
            self.last_name
        )

    def serialize(self, obj_type="Person"):
        data = SerializerMixin.serialize(self, "Person")
        data["full_name"] = self.full_name()
        return data

    def serialize_safe(self):
        data = SerializerMixin.serialize(self, "Person")
        data["full_name"] = self.full_name()
        del data["password"]
        return data
Example #4
0
class OutputFile(db.Model, BaseMixin, SerializerMixin):
    """
    Describe a file generated from a CG artist scene. It's the result of a
    publication.
    It is linked to a working file, an entity and a task type.
    """
    shotgun_id = db.Column(db.Integer())

    name = db.Column(db.String(250), nullable=False)
    extension = db.Column(db.String(10))
    revision = db.Column(db.Integer(), nullable=False)
    representation = db.Column(db.String(20), index=True)
    nb_elements = db.Column(db.Integer(), default=1)

    path = db.Column(db.String(400))

    description = db.Column(db.Text())
    comment = db.Column(db.Text())
    size = db.Column(db.Integer())
    checksum = db.Column(db.String(32))
    source = db.Column(db.String(40))

    canceled = db.Column(db.Boolean(), default=False, nullable=False)

    file_status_id = db.Column(UUIDType(binary=False),
                               db.ForeignKey("file_status.id"),
                               nullable=False)
    entity_id = db.Column(UUIDType(binary=False), db.ForeignKey("entity.id"))
    asset_instance_id = db.Column(UUIDType(binary=False),
                                  db.ForeignKey("asset_instance.id"),
                                  index=True)
    output_type_id = db.Column(UUIDType(binary=False),
                               db.ForeignKey("output_type.id"),
                               index=True)
    task_type_id = db.Column(UUIDType(binary=False),
                             db.ForeignKey("task_type.id"),
                             index=True)
    person_id = db.Column(UUIDType(binary=False), db.ForeignKey("person.id"))
    source_file_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey("working_file.id"),
    )
    source_file = relationship("WorkingFile", back_populates="outputs")
    temporal_entity_id = db.Column(UUIDType(binary=False),
                                   db.ForeignKey("entity.id"),
                                   default=None,
                                   nullable=True)

    __table_args__ = (db.UniqueConstraint("name",
                                          "entity_id",
                                          "asset_instance_id",
                                          "output_type_id",
                                          "task_type_id",
                                          "temporal_entity_id",
                                          "representation",
                                          "revision",
                                          name="output_file_uc"), )

    def __repr__(self):
        return "<OutputFile %s>" % self.id
Example #5
0
class Playlist(db.Model, BaseMixin, SerializerMixin):
    """
    Describes a playlist. The goal is to review a set of shipped materials.
    """

    name = db.Column(db.String(80), nullable=False)
    shots = db.Column(JSONB)

    project_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey("project.id"),
                           index=True)
    episode_id = db.Column(UUIDType(binary=False),
                           db.ForeignKey("entity.id"),
                           index=True)
    for_client = db.Column(db.Boolean(), default=False, index=True)
    for_entity = db.Column(db.String(10), default="shot", index=True)
    is_for_all = db.Column(db.Boolean, default=False)

    build_jobs = relationship("BuildJob")

    __table_args__ = (db.UniqueConstraint("name",
                                          "project_id",
                                          "episode_id",
                                          name="playlist_uc"), )

    @classmethod
    def create_from_import(cls, data):
        del data["type"]
        del data["build_jobs"]
        previous_data = cls.get(data["id"])
        if previous_data is None:
            return cls.create(**data)
        else:
            previous_data.update(data)
            return previous_data
Example #6
0
class MetadataDescriptor(db.Model, BaseMixin, SerializerMixin):
    """
    This models allow to identify which metadata are available for a given
    project and a given entity type.
    """

    project_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey("project.id"),
        nullable=False,
        index=True,
    )
    entity_type = db.Column(db.String(60), nullable=False, index=True)
    name = db.Column(db.String(120), nullable=False)
    field_name = db.Column(db.String(120), nullable=False)
    choices = db.Column(JSONB)
    for_client = db.Column(db.Boolean(), default=False, index=True)

    __table_args__ = (db.UniqueConstraint("project_id",
                                          "entity_type",
                                          "name",
                                          name="metadata_descriptor_uc"), )

    def __repr__(self):
        return "<MetadataDescriptor %s>" % self.id
Example #7
0
class Person(db.Model, BaseMixin, SerializerMixin):

    first_name = db.Column(db.String(80), nullable=False)
    last_name = db.Column(db.String(80), nullable=False)
    email = db.Column(EmailType, unique=True)
    phone = db.Column(db.String(30))
    active = db.Column(db.Boolean(), default=True)
    last_presence = db.Column(db.Date())
    password = db.Column(db.Binary(60))
    shotgun_id = db.Column(db.Integer, unique=True)
    timezone = db.Column(TimezoneType(backend="pytz"),
                         default=pytz_timezone("Europe/Paris"))
    locale = db.Column(LocaleType, default=Locale("en", "US"))

    data = db.Column(JSONB)

    skills = db.relationship("Department", secondary=department_link)

    def __repr__(self):
        return "<Person %s>" % self.full_name()

    def full_name(self):
        if sys.version_info[0] < 3:
            return "%s %s" % (self.first_name.encode("utf-8"),
                              self.last_name.encode("utf-8"))
        else:
            return "%s %s" % (self.first_name, self.last_name)
Example #8
0
class Project(db.Model, BaseMixin, SerializerMixin):
    """
    Describes a CG production the studio works on.
    """
    name = db.Column(db.String(80), nullable=False, unique=True, index=True)
    code = db.Column(db.String(80))
    description = db.Column(db.String(200))
    shotgun_id = db.Column(db.Integer)
    file_tree = db.Column(JSONB)
    data = db.Column(JSONB)
    has_avatar = db.Column(db.Boolean(), default=False)
    fps = db.Column(db.String(10))
    ratio = db.Column(db.String(10))
    resolution = db.Column(db.String(12))
    production_type = db.Column(db.String(20), default="short")
    start_date = db.Column(db.Date())
    end_date = db.Column(db.Date())
    man_days = db.Column(db.Integer)

    project_status_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey('project_status.id'),
        index=True
    )

    team = db.relationship(
        "Person",
        secondary="project_person_link"
    )
Example #9
0
class Organisation(db.Model, BaseMixin, SerializerMixin):
    """
    Model to represent current organisation settings.
    """
    name = db.Column(db.String(80), unique=True, nullable=False)
    hours_by_day = db.Column(db.Integer(), default=8, nullable=False)
    has_avatar = db.Column(db.Boolean(), default=False)
    use_original_file_name = db.Column(db.Boolean(), default=False)

    def present(self):
        return fields.serialize_dict({
            "id": self.id,
            "name": self.name,
            "has_avatar": self.has_avatar,
            "hours_by_day": self.hours_by_day,
            "use_original_file_name": self.use_original_file_name
        })
Example #10
0
class Project(db.Model, BaseMixin, SerializerMixin):
    """
    Describes a CG production the studio works on.
    """

    name = db.Column(db.String(80), nullable=False, unique=True, index=True)
    code = db.Column(db.String(80))
    description = db.Column(db.String(200))
    shotgun_id = db.Column(db.Integer)
    file_tree = db.Column(JSONB)
    data = db.Column(JSONB)
    has_avatar = db.Column(db.Boolean(), default=False)
    fps = db.Column(db.String(10))
    ratio = db.Column(db.String(10))
    resolution = db.Column(db.String(12))
    production_type = db.Column(db.String(20), default="short")
    start_date = db.Column(db.Date())
    end_date = db.Column(db.Date())
    man_days = db.Column(db.Integer)

    project_status_id = db.Column(UUIDType(binary=False),
                                  db.ForeignKey("project_status.id"),
                                  index=True)

    team = db.relationship("Person", secondary="project_person_link")

    def set_team(self, person_ids):
        for person_id in person_ids:
            link = ProjectPersonLink.query.filter_by(
                project_id=self.id, person_id=person_id).first()
            if link is None:
                link = ProjectPersonLink(project_id=self.id,
                                         person_id=person_id)
                db.session.add(link)
        db.session.commit()

    @classmethod
    def create_from_import(cls, data):
        previous_project = cls.get(data["id"])
        person_ids = data.get("team", None)
        del data["team"]
        del data["type"]

        if "project_status_name" in data:
            del data["project_status_name"]

        if previous_project is None:
            previous_project = cls.create(**data)
            previous_project.save()
        else:
            previous_project.update(data)
            previous_project.save()

        if person_ids is not None:
            previous_project.set_team(person_ids)

        return previous_project
Example #11
0
class CustomAction(db.Model, BaseMixin, SerializerMixin):
    """
    Custom actions are HTTP links that can be activated outside of the API.
    They are mainly aimed at being used by the web frontend to allow studio
    to make custom HTTP calls.
    """
    name = db.Column(db.String(80), nullable=False)
    url = db.Column(db.String(400))
    entity_type = db.Column(db.String(40), default="all")
    is_ajax = db.Column(db.Boolean(), default=False)
Example #12
0
class AssetInstance(db.Model, BaseMixin, SerializerMixin):
    """
    An asset instance is the representation of an asset in a given shot or
    layout scene. It is useful for complex scenes where an asset needs extra
    treatments only related to the given shot or layout scene.
    An asset can have multiple instances in a scene or in a shot (ex: a sword in
    a battle field).
    """
    asset_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey('entity.id'),
        nullable=False,
        index=True
    )
    name = db.Column(db.String(80))
    number = db.Column(db.Integer())
    description = db.Column(db.String(200))
    active = db.Column(db.Boolean(), default=True)
    data = db.Column(JSONB)

    scene_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey('entity.id'),
        index=True
    )

    __table_args__ = (
        db.UniqueConstraint(
            'asset_id',
            'scene_id',
            'number',
            name='asset_instance_uc'
        ),
        db.UniqueConstraint(
            'scene_id',
            'name',
            name='asset_instance_name_uc'
        )
    )

    # Do not use these column. They are deprecated and will be dropped in
    # upcoming version
    entity_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey('entity.id'),
    )
    entity_type_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey('entity_type.id')
    )

    def __repr__(self):
        return "<AssetInstance %s>" % self.id
Example #13
0
class Project(db.Model, BaseMixin, SerializerMixin):
    """
    Describes a CG production the studio works on.
    """

    name = db.Column(db.String(80), nullable=False, unique=True, index=True)
    code = db.Column(db.String(80))
    description = db.Column(db.Text())
    shotgun_id = db.Column(db.Integer)
    file_tree = db.Column(JSONB)
    data = db.Column(JSONB)
    has_avatar = db.Column(db.Boolean(), default=False)
    fps = db.Column(db.String(10))
    ratio = db.Column(db.String(10))
    resolution = db.Column(db.String(12))
    production_type = db.Column(db.String(20), default="short")
    start_date = db.Column(db.Date())
    end_date = db.Column(db.Date())
    man_days = db.Column(db.Integer)
    nb_episodes = db.Column(db.Integer, default=0)
    episode_span = db.Column(db.Integer, default=0)

    project_status_id = db.Column(
        UUIDType(binary=False), db.ForeignKey("project_status.id"), index=True
    )

    team = db.relationship("Person", secondary="project_person_link")
    asset_types = db.relationship(
        "EntityType", secondary="project_asset_type_link"
    )
    task_statuses = db.relationship(
        "TaskStatus", secondary="project_task_status_link"
    )
    task_types = db.relationship(
        "TaskType", secondary="project_task_type_link"
    )

    def set_team(self, person_ids):
        for person_id in person_ids:
            link = ProjectPersonLink.query.filter_by(
                project_id=self.id, person_id=person_id
            ).first()
            if link is None:
                link = ProjectPersonLink(
                    project_id=self.id, person_id=person_id
                )
                db.session.add(link)
        db.session.commit()

    def set_task_types(self, task_type_ids):
        return self.set_links(
            task_type_ids,
            ProjectTaskTypeLink,
            "project_id",
            "task_type_id"
        )

    def set_task_statuses(self, task_status_ids):
        return self.set_links(
            task_status_ids,
            ProjectTaskStatusLink,
            "project_id",
            "task_status_id",
        )

    def set_asset_types(self, asset_type_ids):
        return self.set_links(
            asset_type_ids,
            ProjectAssetTypeLink,
            "project_id",
            "asset_type_id"
        )

    @classmethod
    def create_from_import(cls, data):
        is_update = False
        previous_project = cls.get(data["id"])
        data.pop("team", None)
        data.pop("type", None)
        data.pop("project_status_name", None)
        person_ids = data.pop("team", None)
        task_type_ids = data.pop("task_types", None)
        task_status_ids = data.pop("task_statuses", None)
        asset_type_ids = data.pop("asset_types", None)

        if previous_project is None:
            previous_project = cls.create(**data)
            previous_project.save()
        else:
            is_update = True
            previous_project.update(data)
            previous_project.save()

        if person_ids is not None:
            previous_project.set_team(person_ids)

        if task_type_ids is not None:
            previous_project.set_task_types(task_type_ids)

        if task_status_ids is not None:
            previous_project.set_task_statuses(task_status_ids)

        if asset_type_ids is not None:
            previous_project.set_asset_types(asset_type_ids)

        return (previous_project, is_update)
Example #14
0
class Person(db.Model, BaseMixin, SerializerMixin):
    """
    Describe a member of the studio (and an API user).
    """

    first_name = db.Column(db.String(80), nullable=False)
    last_name = db.Column(db.String(80), nullable=False)
    email = db.Column(EmailType, unique=True)
    phone = db.Column(db.String(30))

    active = db.Column(db.Boolean(), default=True)
    last_presence = db.Column(db.Date())

    password = db.Column(db.LargeBinary(60))
    desktop_login = db.Column(db.String(80))
    shotgun_id = db.Column(db.Integer, unique=True)
    timezone = db.Column(
        TimezoneType(backend="pytz"),
        default=pytz_timezone(config.DEFAULT_TIMEZONE),
    )
    locale = db.Column(LocaleType, default=Locale("en", "US"))
    data = db.Column(JSONB)
    role = db.Column(db.String(30), default="user")
    has_avatar = db.Column(db.Boolean(), default=False)

    notifications_enabled = db.Column(db.Boolean(), default=False)
    notifications_slack_enabled = db.Column(db.Boolean(), default=False)
    notifications_slack_userid = db.Column(db.String(60), default="")
    notifications_mattermost_enabled = db.Column(db.Boolean(), default=False)
    notifications_mattermost_userid = db.Column(db.String(60), default="")
    notifications_discord_enabled = db.Column(db.Boolean(), default=False)
    notifications_discord_userid = db.Column(db.String(60), default="")

    departments = db.relationship("Department",
                                  secondary=department_link,
                                  lazy="joined")

    def __repr__(self):
        if sys.version_info[0] < 3:
            return "<Person %s>" % self.full_name().encode("utf-8")
        else:
            return "<Person %s>" % self.full_name()

    def full_name(self):
        return "%s %s" % (self.first_name, self.last_name)

    def serialize(self, obj_type="Person", relations=False):
        data = SerializerMixin.serialize(self, "Person", relations=relations)
        data["full_name"] = self.full_name()
        return data

    def serialize_safe(self, relations=False):
        data = SerializerMixin.serialize(self, "Person", relations=relations)
        data["full_name"] = self.full_name()
        del data["password"]
        return data

    def present_minimal(self, relations=False):
        data = SerializerMixin.serialize(self, "Person", relations=relations)
        return {
            "id": data["id"],
            "first_name": data["first_name"],
            "last_name": data["last_name"],
            "full_name": self.full_name(),
            "has_avatar": data["has_avatar"],
            "active": data["active"],
            "departments": data.get("departments", []),
            "role": data["role"],
        }

    def set_departments(self, department_ids):
        from zou.app.models.department import Department

        self.departments = []
        for department_id in department_ids:
            department = Department.get(department_id)
            if department is not None:
                self.departments.append(department)
        self.save()

    @classmethod
    def create_from_import(cls, person):
        del person["type"]
        del person["full_name"]
        is_update = False
        previous_person = cls.get(person["id"])

        if "password" in person:
            person["password"] = person["password"].encode()

        department_ids = None
        if "departments" in person:
            department_ids = person.pop("departments", None)

        if previous_person is None:
            previous_person = cls.create(**person)
        else:
            is_update = True
            previous_person.update(person)

        if department_ids is not None:
            previous_person.set_departments(department_ids)

        return (previous_person, is_update)
Example #15
0
class OutputFile(db.Model, BaseMixin, OutputFileSerializer):
    """
    Describe a file generated from a CG artist scene. It's the result of a
    publication.
    It is linked to a working/ children/ dependent file, an entity and a task type.
    """
    __tablename__ = "output_file"

    shotgun_id = db.Column(db.String(50))

    name = db.Column(db.String(250), nullable=False)
    canceled = db.Column(db.Boolean(), default=False, nullable=False) # surement une forme d'"omit"
    size = db.Column(db.Integer())
    checksum = db.Column(db.String(32))
    description = db.Column(db.Text())
    comment = db.Column(db.Text())
    extension = db.Column(db.String(10))
    revision = db.Column(db.Integer(), nullable=False) # version
    representation = db.Column(db.String(20), index=True) # une manière de regrouper (ex: par extension)
    nb_elements = db.Column(db.Integer(), default=1) # à refaire, pas de start-end
    source = db.Column(db.String(40)) # permet de dire d'où ça vient (ex: muster)
    path = db.Column(db.String(400))
    data = db.Column(JSONB)

    file_status_id = db.Column(
        UUIDType(binary=False), db.ForeignKey("file_status.id"), nullable=False
    )
    entity_id = db.Column(UUIDType(binary=False), db.ForeignKey("entity.id"))
    asset_instance_id = db.Column(
        UUIDType(binary=False), db.ForeignKey("asset_instance.id"), index=True
    )
    output_type_id = db.Column(
        UUIDType(binary=False), db.ForeignKey("output_type.id"), index=True
    )
    task_type_id = db.Column(
        UUIDType(binary=False), db.ForeignKey("task_type.id"), index=True
    )
    person_id = db.Column(UUIDType(binary=False), db.ForeignKey("person.id"))
    render_info = db.Column(db.String(200))
    source_file_id = db.Column(
        UUIDType(binary=False), db.ForeignKey("working_file.id")
    )
    render_info = db.Column(db.String(200))
    source_file = relationship(
        "WorkingFile", 
        lazy="joined", 
        back_populates="outputs"
    )
    children_files = relationship(
        "ChildrenFile", 
        lazy="joined", 
        backref=backref("parent_file", cascade="all, delete")
    )
    # TODO: by default not serialize it
    dependent_files = relationship(
        "DependentFile",
        secondary=dependent_table,
        back_populates="used_by"
    )
    temporal_entity_id = db.Column(
        UUIDType(binary=False),
        db.ForeignKey("entity.id"),
        default=None,
        nullable=True,
    )

    __table_args__ = (
        db.UniqueConstraint(
            "name",
            "entity_id",
            "asset_instance_id",
            "output_type_id",
            "task_type_id",
            "temporal_entity_id",
            "representation",
            "revision",
            name="output_file_uc",
        ),
    )

    def __repr__(self):
        return "<OutputFile %s>" % self.id
Example #16
0
class Person(db.Model, BaseMixin, SerializerMixin):
    """
    Describe a member of the studio (and an API user).
    """

    first_name = db.Column(db.String(80), nullable=False)
    last_name = db.Column(db.String(80), nullable=False)
    email = db.Column(EmailType, unique=True)
    phone = db.Column(db.String(30))

    active = db.Column(db.Boolean(), default=True)
    last_presence = db.Column(db.Date())

    password = db.Column(db.LargeBinary(60))
    desktop_login = db.Column(db.String(80))
    shotgun_id = db.Column(db.Integer, unique=True)
    timezone = db.Column(TimezoneType(backend="pytz"),
                         default=pytz_timezone("Europe/Paris"))
    locale = db.Column(LocaleType, default=Locale("en", "US"))
    data = db.Column(JSONB)
    role = db.Column(db.String(30), default="user")
    has_avatar = db.Column(db.Boolean(), default=False)

    notifications_enabled = db.Column(db.Boolean(), default=False)
    notifications_slack_enabled = db.Column(db.Boolean(), default=False)
    notifications_slack_userid = db.Column(db.String(60), default="")

    skills = db.relationship("Department", secondary=department_link)

    def __repr__(self):
        if sys.version_info[0] < 3:
            return "<Person %s>" % self.full_name().encode("utf-8")
        else:
            return "<Person %s>" % self.full_name()

    def full_name(self):
        return "%s %s" % (self.first_name, self.last_name)

    def serialize(self, obj_type="Person", relations=False):
        data = SerializerMixin.serialize(self, "Person", relations=relations)
        data["full_name"] = self.full_name()
        return data

    def serialize_safe(self, relations=False):
        data = SerializerMixin.serialize(self, "Person", relations=relations)
        data["full_name"] = self.full_name()
        del data["password"]
        return data

    def present_minimal(self, relations=False):
        data = SerializerMixin.serialize(self, "Person", relations=relations)
        return {
            "id": data["id"],
            "first_name": data["first_name"],
            "last_name": data["last_name"],
            "full_name": self.full_name(),
            "has_avatar": data["has_avatar"],
            "active": data["active"],
            "desktop_login": data["desktop_login"]
        }

    @classmethod
    def create_from_import(cls, person):
        del person["type"]
        del person["full_name"]
        previous_person = cls.get(person["id"])
        if "password" in person:
            person["password"] = person["password"].encode()
        if previous_person is None:
            return (cls.create(**person), False)
        else:
            previous_person.update(person)
            return (previous_person, True)