Пример #1
0
class Project(Base):
    """Project is a container for tickets."""
    pkey = db.Column(db.String(6), nullable=False, unique=True)
    name = db.Column(db.String(250), nullable=False)
    repo = db.Column(db.String(250))
    homepage = db.Column(db.String(250))

    project_lead_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    team_id = db.Column(db.Integer, db.ForeignKey('team.id'))

    tickets = db.relationship('Ticket', backref='project', lazy='dynamic')
    members = db.relationship('Membership', backref='project', lazy='dynamic')

    def __init__(self, *, pkey, name, repo='', homepage=''):
        self.pkey = pkey.upper()
        self.name = name
        self.repo = repo
        self.homepage = homepage

    def get_by_key(team_slug, pkey, preload=False):
        p = Project.query.\
                join(Project.team).\
                filter(Team.url_slug == team_slug).\
                filter(Project.pkey == pkey).\
                first()
        if p == None:
            raise AppError(status_code=404,
                           message="That project does not exist.")
        return p

    def __repr__(self):
        return "<Project %r>" % (self.pkey)
Пример #2
0
class Ticket(Base):
    """A ticket is a unit of work for a project, be it a bug or support ticket."""
    ticket_key = db.Column(db.String(100), nullable=False,
                           unique=True)  # I mean jesus christ how many digits
    summary = db.Column(db.String(250), nullable=False)
    description = db.Column(db.Text())

    assignee_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    reporter_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    project_id = db.Column(db.Integer, db.ForeignKey('project.id'))

    def __init__(self,
                 *,
                 ticket_key,
                 summary,
                 description,
                 assignee_id=None,
                 reporter_id=None):
        self.ticket_key = ticket_key
        self.summary = summary
        self.description = description
        self.assignee_id = assignee_id
        self.reporter_id = reporter_id

    def __repr__(self):
        return "<Ticket %r>" % (self.ticket_key)
Пример #3
0
class Ticket(Base):
    """A ticket is a unit of work for a project, be it a bug or support ticket."""
    ticket_key  = db.Column(db.String(100), nullable=False, unique=True) # I mean jesus christ how many digits
    summary     = db.Column(db.String(250), nullable=False)
    description = db.Column(db.Text())

    assignee_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    reporter_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    project_id  = db.Column(db.Integer, db.ForeignKey('project.id'))
    status_id   = db.Column(db.Integer, db.ForeignKey('status.id'))

    fields      = db.relationship('FieldValue', backref='ticket')
    comments    = db.relationship('Comment', backref='ticket', lazy='dynamic')

    def __init__(self, *, ticket_key, summary, description, assignee_id=None, reporter_id=None):
        self.ticket_key  = ticket_key
        self.summary     = summary
        self.description = description
        self.assignee_id = assignee_id
        self.reporter_id = reporter_id

    def get_by_id(i, preload=''):
        tk = Ticket.query.\
                options(joinedload(Ticket.status)).\
                options(joinedload(Ticket.reporter)).\
                options(joinedload(Ticket.assignee)).\
                filter(Ticket.id == i)
        return tk.first()

    def get_by_key(team_slug, pkey, ticket_key, preload=''):
        tk = Ticket.query.\
                options(joinedload(Ticket.status)).\
                options(joinedload(Ticket.reporter)).\
                options(joinedload(Ticket.assignee)).\
                join(Ticket.project).\
                join(Project.team).\
                filter(Team.url_slug == team_slug).\
                filter(Project.pkey == pkey).\
                filter(Ticket.ticket_key == ticket_key)
        if 'project' in preload.lower():
            tk = tk.options(joinedload(Ticket.project))
        return tk.first()

    def from_json(pkey, json):
        validate(json, ticket_schema)
        prjct = Project.get_by_key(pkey)
        r = User.get_by_username_or_id(json.get("reporter", {}).get("username", ""))
        a = User.get_by_username_or_id(json.get("assignee", {}).get("username", ""))
        tk = Ticket(summary=json['summary'],
                   description=json['description'],
                   ticket_key=prjct.pkey + "-" + str(len(prjct.tickets) + 1),
                   reporter_id=r.id,
                   project_id=prjct.id)
        if a != None:
            tk.assignee_id = a.id
        return tk

    def __repr__(self):
        return '<Ticket %r>' % (self.ticket_key)
Пример #4
0
class Project(Base):
    """Project is a container for tickets."""
    pkey     = db.Column(db.String(6), nullable=False, unique=True)
    name     = db.Column(db.String(250), nullable=False)
    repo     = db.Column(db.String(250))
    homepage = db.Column(db.String(250))

    project_lead_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    team_id         = db.Column(db.Integer, db.ForeignKey('team.id'))

    tickets = db.relationship('Ticket', backref='project')
    members = db.relationship('Membership', backref='project', lazy='dynamic')

    def __init__(self, *, pkey, name, repo='', homepage=''):
        self.pkey     = pkey.upper()
        self.name     = name
        self.repo     = repo
        self.homepage = homepage

    def get_by_id(i, preload=''):
       p = Project.query.\
                options(joinedload(Project.project_lead)).\
                filter(Project.id == i).\
                first()
       return p

    def get_by_key(team_slug, pkey, preload=''):
        p = Project.query.\
                options(joinedload(Project.project_lead)).\
                join(Project.team).\
                filter(Team.url_slug == team_slug).\
                filter(Project.pkey == pkey).\
                first()
        return p

    def from_json(team_slug, jsn):
        validate(jsn, project_schema)
        t = Team.get_by_slug(team_slug)
        p = Project(pkey=jsn["pkey"],
                    name=jsn["name"],
                    homepage=jsn.get("homepage", ""),
                    repo=jsn.get("repo", ""))
        p.team = t
        return p

    def to_json(self):
        return super().to_json(ignoreFields=["updated_at"])

    def __repr__(self):
        return "<Project %r>" % (self.pkey)
Пример #5
0
class FieldValue(Base):
    field_id = db.Column('field_id',
                         db.Integer,
                         db.ForeignKey('field.id'),
                         nullable=False)
    ticket_id = db.Column('ticket_id',
                          db.Integer,
                          db.ForeignKey('ticket.id'),
                          nullable=False)
    text_value = db.Column(db.Text())
    string_value = db.Column(db.String(250))
    float_value = db.Column(db.Float)
    integer_value = db.Column(db.Integer)

    def validate_value(self):
        if ((self.field.data_type == DataTypes.INTEGER
             and type(self.value) is not int)
                or (self.field.data_type == DataTypes.FLOAT
                    and type(self.value) is not float)
                or (self.field.data_type == DataTypes.TEXT
                    and type(self.value) is not str)
                or (self.field.data_type == DataTypes.STRING
                    and type(self.value) is not str)):
            raise AppError(status_code=400,
                           message='Invalid type for the field: ' + self.name)

    def set_value(self):
        self.validate_value()
        if self.field.data_type == DataTypes.INTEGER:
            self.integer_value = self.value
        elif self.field.data_type == DataTypes.FLOAT:
            self.float_value = self.value
        elif self.field.data_type == DataTypes.TEXT:
            self.text_value = self.value
        elif self.field.data_type == DataTypes.STRING:
            self.string_value = self.value
        else:
            raise AppError(status_code=500,
                           message='Uknown error setting field value')

    def from_json(jsn):
        parent_field = Field.query.filter_by(name=jsn.get("name", ""))
        if parent_field == None:
            raise AppError(status_code=404, message="No field with that name")
        fv = FieldValue(name=jsn.get("name"), value=jsn.get("value"))
        fv.set_value()
        return fv
Пример #6
0
class Comment(Base):
    """A comment on a ticket"""
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    ticket_id = db.Column(db.Integer, db.ForeignKey('ticket.id'))

    body = db.Column(db.Text())

    def __init__(self, ticket=None, author=None, *, body):
        self.ticket = ticket
        self.author = author
        self.body = body

    def to_json(self):
        s = super().to_json()
        s.pop('author_id', None)
        s.pop('ticket_id', None)
        return s

    def from_json(json):
        validate(json, comment_schema)
        u = User.get_by_username_or_id(j['author']['username'])
        c = Comment(body=json['body'], author=u)
        return c

    def get_all(team_slug, pkey, ticket_key):
        cmts = Comment.query.\
                options(joinedload(Comment.author)).\
                join(Comment.ticket).\
                join(Ticket.project).\
                join(Project.team).\
                filter(Ticket.ticket_key == ticket_key).\
                filter(Project.pkey == pkey).\
                filter(Team.url_slug == team_slug).\
                all()
        return cmts

    def get_for_ticket(ticket):
        cmts = Comment.query.\
                join(Comment.ticket).\
                filter(Comment.ticket_id == ticket.id)
        return cmts
Пример #7
0
class Team(Base):
    """Team is a container for projects.
    
    When changing the name for a team use set_name as this properly updates
    dependent fields for Team. YOU WILL HAVE A BAD TIME IF YOU DO team.name =
    SOME_NAME.
    """
    name = db.Column(db.String(120), nullable=False, unique=True)
    url_slug = db.Column(db.String(150), nullable=False, unique=True)
    icon = db.Column(db.String(150))

    team_lead_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    projects = db.relationship('Project', backref='team', lazy='dynamic')
    members = db.relationship('Membership', backref='team', lazy='dynamic')

    def __init__(self, *, name, icon=""):
        self.name = name
        self.url_slug = name.lower().replace(" ", "-")
        self.icon = icon

    def set_name(self, name):
        self.name = name
        self.url_slug = name.lower().replace(" ", "-")

    def from_json(json):
        validate(json, team_schema)
        t = Team(name=json["name"], icone=json.get("icon", ""))
        un = json.get("project_lead", {}).get("username", "")
        lead = User.query.filter_by(username=un).first()
        t.team_lead = lead
        return t

    def get_by_name_or_stub(name):
        t = Team.query.filter(or_(Team.name == name,
                                  Team.url_stub == name)).first()
        if t == None:
            raise AppError(status_code=404, message="That team does not exist")
        return t

    def from_json(json):
        validate(json, team_schema)
        t = Team(name=json["name"], icone=json.get("icon", ""))
        un = json.get("project_lead", {}).get("username", "")
        lead = User.query.filter_by(username=un).first()
        t.team_lead = lead
        return t

    def __repr__(self):
        return "<Team %r>" % (self.name)
Пример #8
0
class Membership(Base):
    """Membership is used to control access and permissions for a project or
    team.
    
    Permission levels are stored as Integers and there are three permission
    levels.

    0 = User
    1 = Contributor
    2 = Administrator
    """
    team_id = db.Column(db.Integer, db.ForeignKey('team.id'))
    project_id = db.Column(db.Integer, db.ForeignKey('project.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    permission_level = db.Column(db.Integer)

    def __init__(self, perm):
        self.permission_level = perm

    def get_project_memberships(team_slug, pkey):
        m = Membership.query.\
                join(Membership.project).\
                join(Membership.user).\
                join(Project.team).\
                filter(Team.url_slug == url_slug).\
                filter(Project.pkey == pkey).\
                all()
        if m == None:
            raise AppError(status_code=404,
                           message="Project or team not found.")
        return m

    def __repr__(self):
        return "<Membership %r %r %r %r>" % (
            self.team_id, self.project_id, self.user_id, self.permission_level)
Пример #9
0
class Team(Base):
    """Team is a container for projects.
    
    When changing the name for a team use set_name as this properly updates
    dependent fields for Team. YOU WILL HAVE A BAD TIME IF YOU DO team.name =
    SOME_NAME.
    """
    name = db.Column(db.String(120), nullable=False, unique=True)
    url_slug = db.Column(db.String(150), nullable=False, unique=True)
    icon = db.Column(db.String(150))

    team_lead_id = db.Column(db.Integer, db.ForeignKey('users.id'))

    projects = db.relationship('Project', backref='team', lazy='dynamic')
    members = db.relationship('Membership', backref='team', lazy='dynamic')

    def __init__(self, *, name, icon=''):
        self.name = name
        self.url_slug = name.lower().replace(' ', '-')
        self.icon = icon

    def set_name(self, name):
        self.name = name
        self.url_slug = name.lower().replace(' ', '-')

    def from_json(json):
        validate(json, team_create_schema)
        t = Team(name=json['name'], icon=json.get('icon', ''))
        un = json.get('project_lead', {}).get('username', '')
        lead = User.query.filter_by(username=un).first()
        t.team_lead = lead
        return t

    def to_json(self):
        return super().to_json(ignoreFields=["updated_at"])

    def get_by_name_or_stub(name):
        t = Team.query.\
                options(joinedload(Team.team_lead)).\
                filter(or_(Team.name == name,
                           Team.url_slug == name)).first()
        print(t.team_lead)
        if t == None:
            raise AppError(status_code=404, message='That team does not exist')
        return t

    def __repr__(self):
        return '<Team %r>' % (self.name)
Пример #10
0
import enum

from tessera import db
from sqlalchemy import CheckConstraint
from tessera.models.v1 import Base

# This table shows us our workflow, we query our next statuses by getting all
# rows with a given status_id and then we can find our previous statuses by
# getting all the rows with next_status_id = our id.
status_relationships = db.Table(
    'status_relationships',
    db.Column('status_id', db.Integer, db.ForeignKey('status.id'),
              nullable=False),
    db.Column('next_status_id', db.Integer, db.ForeignKey('status.id'),
              nullable=False),
    db.PrimaryKeyConstraint('status_id', 'next_status_id')
)

class Status(Base):
    name          = db.Column(db.String(100), nullable=False)
    status_type   = db.Column(db.Enum("TODO", "IN_PROGRESS", "DONE", name='status_types'),
                              nullable=False)
    next_statuses = db.relationship('Status', 
                                    secondary=status_relationships,
                                    primaryjoin="Status.id == status_relationships.c.status_id",
                                    secondaryjoin="Status.id == status_relationships.c.next_status_id", 
                                    backref='previous_statuses',
                                    lazy='dynamic')

    tickets = db.relationship('Ticket', backref='status', lazy='dynamic')
Пример #11
0
from tessera.lib import AppError
from tessera.models.v1.base import Base


class DataTypes(enum.Enum):
    INTEGER = "INTEGER"
    FLOAT = "FLOAT"
    STRING = "STRING"
    TEXT = "TEXT"


project_field_schema = db.Table(
    'project_field_schema',
    db.Column('field_id',
              db.Integer,
              db.ForeignKey('field.id'),
              nullable=False),
    db.Column('project_id',
              db.Integer,
              db.ForeignKey('project.id'),
              nullable=False), db.PrimaryKeyConstraint('field_id',
                                                       'project_id'))


class Field(Base):
    name = db.Column(db.String(100), nullable=False)
    data_type = db.Column(db.Enum("INTEGER",
                                  "FLOAT",
                                  "STRING",
                                  "TEXT",
                                  name="data_types"),