class Organization( Party ):
    """An organization represents any internal or external organization.  Organizations can include
    businesses and groups of individuals"""
    using_options( tablename = 'organization', inheritance = 'multi' )
    name = Field( Unicode( 50 ), required = True, index = True )
    logo = Field( camelot.types.Image( upload_to = 'organization-logo' ), deferred = True )
    tax_id = Field( Unicode( 20 ) )
    directors = OneToMany( 'DirectedDirector', inverse = 'established_from', cascade='all, delete, delete-orphan' )
    employees = OneToMany( 'EmployerEmployee', inverse = 'established_from', cascade='all, delete, delete-orphan' )
    suppliers = OneToMany( 'SupplierCustomer', inverse = 'established_to', cascade='all, delete, delete-orphan' )
    customers = OneToMany( 'SupplierCustomer', inverse = 'established_from', cascade='all, delete, delete-orphan' )
    shareholders = OneToMany( 'SharedShareholder', inverse = 'established_from', cascade='all, delete, delete-orphan' )

    def __unicode__( self ):
        return self.name or ''

    @property
    def number_of_shares_issued( self ):
        return sum( ( shareholder.shares for shareholder in self.shareholders ), 0 )

    class Admin( Party.Admin ):
        verbose_name = _( 'Organization' )
        verbose_name_plural = _( 'Organizations' )
        list_display = ['name', 'tax_id', 'contact_mechanisms_email', 'contact_mechanisms_phone']
        form_display = TabForm( [( _('Basic'), Form( ['name', 'tax_id', 'addresses', 'contact_mechanisms'] ) ),
                                ( _('Employment'), Form( ['employees'] ) ),
                                ( _('Customers'), Form( ['customers'] ) ),
                                ( _('Suppliers'), Form( ['suppliers'] ) ),
                                ( _('Corporate'), Form( ['directors', 'shareholders', 'shares'] ) ),
                                ( _('Branding'), Form( ['logo'] ) ),
                                ( _('Status'), Form( ['status'] ) ),
                                ] )
Beispiel #2
0
class Status(Entity):
    """The status of a release, such as Downloaded, Deleted, Wanted etc"""

    identifier = Field(String(20), unique = True)
    label = Field(Unicode(20))

    releases = OneToMany('Release')
    movies = OneToMany('Movie')
Beispiel #3
0
class Profile(Entity):
    """"""
    using_options(order_by='order')

    label = Field(Unicode(50))
    order = Field(Integer)
    core = Field(Boolean)
    hide = Field(Boolean)

    movie = OneToMany('Movie')
    types = OneToMany('ProfileType', cascade='all, delete-orphan')
Beispiel #4
0
class Release(Entity):
    """Logically groups all files that belong to a certain release, such as
    parts of a movie, subtitles."""

    identifier = Field(String(100))

    movie = ManyToOne('Movie')
    status = ManyToOne('Status')
    quality = ManyToOne('Quality')
    files = ManyToMany('File')
    history = OneToMany('History')
    info = OneToMany('ReleaseInfo')
Beispiel #5
0
class Quality(Entity):
    """Quality name of a release, DVD, 720p, DVD-Rip etc"""
    using_options(order_by = 'order')

    identifier = Field(String(20), unique = True)
    label = Field(Unicode(20))
    order = Field(Integer, default = 0, index = True)

    size_min = Field(Integer)
    size_max = Field(Integer)

    releases = OneToMany('Release')
    profile_types = OneToMany('ProfileType')
Beispiel #6
0
class File(Entity):
    """File that belongs to a release."""

    path = Field(Unicode(255), nullable=False, unique=True)
    part = Field(Integer, default=1)

    type = ManyToOne('FileType')
    properties = OneToMany('FileProperty')

    history = OneToMany('RenameHistory')
    movie = ManyToMany('Movie')
    release = ManyToMany('Release')
    library = ManyToMany('Library')
Beispiel #7
0
class Library(Entity):
    """"""

    year = Field(Integer)
    identifier = Field(String(20), index = True)

    plot = Field(UnicodeText)
    tagline = Field(UnicodeText(255))
    info = Field(JsonType)

    status = ManyToOne('Status')
    movies = OneToMany('Movie', cascade = 'all, delete-orphan')
    titles = OneToMany('LibraryTitle', cascade = 'all, delete-orphan')
    files = ManyToMany('File', cascade = 'all, delete-orphan', single_parent = True)
Beispiel #8
0
class Library(Entity):
    """"""

    year = Field(Integer)
    identifier = Field(String(20))
    rating = Field(Float)

    plot = Field(UnicodeText)
    tagline = Field(UnicodeText(255))

    status = ManyToOne('Status')
    movie = OneToMany('Movie')
    titles = OneToMany('LibraryTitle')
    files = ManyToMany('File')
class ContactMechanism( Entity ):
    using_options( tablename = 'contact_mechanism' )
    mechanism = Field( camelot.types.VirtualAddress( 256 ), required = True )
    party_address = ManyToOne( 'PartyAddress', ondelete = 'set null', onupdate = 'cascade' )
    party_contact_mechanisms = OneToMany( 'PartyContactMechanism' )

    def __unicode__( self ):
        if self.mechanism:
            return u'%s : %s' % ( self.mechanism[0], self.mechanism[1] )

    class Admin( EntityAdmin ):
        form_size = ( 700, 150 )
        verbose_name = _('Contact mechanism')
        list_display = ['mechanism']
        form_display = Form( ['mechanism', 'party_address'] )
        field_attributes = {'mechanism':{'minimal_column_width':25}}

        def get_depending_objects(self, contact_mechanism ):
            for party_contact_mechanism in contact_mechanism.party_contact_mechanisms:
                if party_contact_mechanism not in PartyContactMechanism.query.session.new:
                    party_contact_mechanism.expire( ['mechanism'] )
                    yield party_contact_mechanism
                    party = party_contact_mechanism.party
                    if party and party not in Party.query.session.new:
                        party.expire(['email', 'phone'])
                        yield party
Beispiel #10
0
class Release(Entity):
    """Logically groups all files that belong to a certain release, such as
    parts of a movie, subtitles."""

    identifier = Field(String(100), index=True)

    movie = ManyToOne('Movie')
    status = ManyToOne('Status')
    quality = ManyToOne('Quality')
    files = ManyToMany('File',
                       cascade='all, delete-orphan',
                       single_parent=True)
    info = OneToMany('ReleaseInfo', cascade='all, delete-orphan')

    def to_dict(self, deep={}, exclude=[]):
        orig_dict = super(Release, self).to_dict(deep=deep, exclude=exclude)

        new_info = {}
        for info in orig_dict.get('info', []):

            value = info['value']
            try:
                value = int(info['value'])
            except:
                pass

            new_info[info['identifier']] = value

        orig_dict['info'] = new_info

        return orig_dict
Beispiel #11
0
class Release(Entity):
    """Logically groups all files that belong to a certain release, such as
    parts of a movie, subtitles."""

    last_edit = Field(Integer, default = lambda: int(time.time()), index = True)
    identifier = Field(String(100), index = True)

    movie = ManyToOne('Movie')
    status = ManyToOne('Status')
    quality = ManyToOne('Quality')
    files = ManyToMany('File')
    info = OneToMany('ReleaseInfo', cascade = 'all, delete-orphan')

    def to_dict(self, deep = None, exclude = None):
        if not exclude: exclude = []
        if not deep: deep = {}

        orig_dict = super(Release, self).to_dict(deep = deep, exclude = exclude)

        new_info = {}
        for info in orig_dict.get('info', []):

            value = info['value']
            try: value = int(info['value'])
            except: pass

            new_info[info['identifier']] = value

        orig_dict['info'] = new_info

        return orig_dict
class DirectedDirector( PartyRelationship ):
    """Relation from a directed organization to a director"""
    using_options( tablename = 'party_relationship_dir', inheritance = 'multi' )
    established_from = ManyToOne( 'Organization', required = True, ondelete = 'cascade', onupdate = 'cascade' )
    established_to = ManyToOne( 'Party', required = True, ondelete = 'cascade', onupdate = 'cascade' )
    title = Field( Unicode( 256 ) )
    represented_by = OneToMany( 'RepresentedRepresentor', inverse = 'established_to' )

    class Admin( PartyRelationship.Admin ):
        verbose_name = _('Direction structure')
        verbose_name_plural = _('Direction structures')
        list_display = ['established_from', 'established_to', 'title', 'represented_by']
        list_search = ['established_from.full_name', 'established_to.full_name']
        field_attributes = {'established_from':{'name':_('Organization')},
                            'established_to':{'name':_('Director')}}

    class DirectorAdmin( Admin ):
        verbose_name = _('Director')
        list_display = ['established_to', 'title', 'from_date', 'thru_date']
        form_display = ['established_to', 'title', 'from_date', 'thru_date', 'represented_by', 'comment']

    class DirectedAdmin( Admin ):
        verbose_name = _('Directed organization')
        list_display = ['established_from', 'title', 'from_date', 'thru_date']
        form_display = ['established_from', 'title', 'from_date', 'thru_date', 'represented_by', 'comment']
Beispiel #13
0
class LibraryTitle(Entity):
    """"""

    title = Field(Unicode)
    default = Field(Boolean)

    language = OneToMany('Language')
    libraries = ManyToOne('Library')
Beispiel #14
0
class FileType(Entity):
    """Types could be trailer, subtitle, movie, partial movie etc."""

    identifier = Field(String(20), unique = True)
    type = Field(Unicode(20))
    name = Field(Unicode(50), nullable = False)

    files = OneToMany('File')
Beispiel #15
0
class Release(Entity):
    """Logically groups all files that belong to a certain release, such as
    parts of a movie, subtitles."""

    movie = ManyToOne('Movie')
    status = ManyToOne('Status')
    quality = ManyToOne('Quality')
    files = ManyToMany('File')
    history = OneToMany('History')
Beispiel #16
0
class Profile(Entity):
    """"""
    using_options(order_by='order')

    label = Field(Unicode(50))
    order = Field(Integer, default=0, index=True)
    core = Field(Boolean, default=False)
    hide = Field(Boolean, default=False)

    movie = OneToMany('Movie')
    types = OneToMany('ProfileType', cascade='all, delete-orphan')

    def to_dict(self, deep={}, exclude=[]):
        orig_dict = super(Profile, self).to_dict(deep=deep, exclude=exclude)
        orig_dict['core'] = orig_dict.get('core') or False
        orig_dict['hide'] = orig_dict.get('hide') or False

        return orig_dict
Beispiel #17
0
class Library(Entity):
    """"""

    year = Field(Integer)
    identifier = Field(String(20))
    rating = Field(Float)

    plot = Field(UnicodeText)
    tagline = Field(UnicodeText(255))

    status = ManyToOne('Status')
    movies = OneToMany('Movie')
    titles = OneToMany('LibraryTitle')
    files = ManyToMany('File')
    info = OneToMany('LibraryInfo')

    def title(self):
        return self.titles[0]['title']
Beispiel #18
0
class LibraryTitle(Entity):
    """"""
    using_options(order_by='-default')

    title = Field(Unicode)
    default = Field(Boolean)

    language = OneToMany('Language')
    libraries = ManyToOne('Library')
Beispiel #19
0
class Movie(Entity):
    """Movie Resource a movie could have multiple releases
    The files belonging to the movie object are global for the whole movie
    such as trailers, nfo, thumbnails"""

    last_edit = Field(Integer)

    library = ManyToOne('Library')
    status = ManyToOne('Status')
    profile = ManyToOne('Profile')
    releases = OneToMany('Release')
    files = ManyToMany('File')
Beispiel #20
0
class Category(Entity):
    """"""
    using_options(order_by = 'order')

    label = Field(Unicode(50))
    order = Field(Integer, default = 0, index = True)
    required = Field(Unicode(255))
    preferred = Field(Unicode(255))
    ignored = Field(Unicode(255))
    destination = Field(Unicode(255))

    movie = OneToMany('Movie')
class Person( Party ):
    """Person represents natural persons
    """
    using_options( tablename = 'person', inheritance = 'multi' )
    first_name = Field( Unicode( 40 ), required = True )
    last_name = Field( Unicode( 40 ), required = True )
# end short person definition
    middle_name = Field( Unicode( 40 ) )
    personal_title = Field( Unicode( 10 ) )
    suffix = Field( Unicode( 3 ) )
    sex = Field( Unicode( 1 ), default = u'M' )
    birthdate = Field( Date() )
    martial_status = Field( Unicode( 1 ) )
    social_security_number = Field( Unicode( 12 ) )
    passport_number = Field( Unicode( 20 ) )
    passport_expiry_date = Field( Date() )
    is_staff = Field( Boolean, default = False, index = True )
    is_superuser = Field( Boolean, default = False, index = True )
    picture = Field( camelot.types.Image( upload_to = 'person-pictures' ), deferred = True )
    comment = Field( camelot.types.RichText() )
    employers = OneToMany( 'EmployerEmployee', inverse = 'established_to', cascade='all, delete, delete-orphan' )

    @property
    def note(self):
        for person in self.__class__.query.filter_by(first_name=self.first_name, last_name=self.last_name):
            if person != self:
                return _('A person with the same name allready exists')

    @property
    def name( self ):
        # we don't use full name in here, because for new objects, full name will be None, since
        # it needs to be fetched from the db first
        return u'%s %s' % ( self.first_name, self.last_name )

    def __unicode__( self ):
        return self.name or ''

    class Admin( Party.Admin ):
        verbose_name = _( 'Person' )
        verbose_name_plural = _( 'Persons' )
        list_display = ['first_name', 'last_name', 'contact_mechanisms_email', 'contact_mechanisms_phone']
        form_display = TabForm( [( _('Basic'), Form( [HBoxForm( [Form( [WidgetOnlyForm('note'), 'first_name', 'last_name', 'sex'] ),
                                                          Form( ['picture', ] ),
                                                         ] ),
                                                         'contact_mechanisms', 'comment', ], scrollbars = False ) ),
                                ( _('Official'), Form( ['birthdate', 'social_security_number', 'passport_number',
                                                        'passport_expiry_date', 'addresses', ], scrollbars = False ) ),
                                ( _('Work'), Form( ['employers', 'directed_organizations', 'shares'], scrollbars = False ) ),
                                ( _('Status'), Form( ['status'] ) ),
                                ] )
        field_attributes = dict( Party.Admin.field_attributes )
        field_attributes['note'] = {'delegate':delegates.NoteDelegate}
Beispiel #22
0
class Movie(Entity):
    """Movie Resource a movie could have multiple releases
    The files belonging to the movie object are global for the whole movie
    such as trailers, nfo, thumbnails"""

    last_edit = Field(Integer, default = lambda: int(time.time()), index = True)
    type = 'movie'  # Compat tv branch

    library = ManyToOne('Library', cascade = 'delete, delete-orphan', single_parent = True)
    status = ManyToOne('Status')
    profile = ManyToOne('Profile')
    category = ManyToOne('Category')
    releases = OneToMany('Release', cascade = 'all, delete-orphan')
    files = ManyToMany('File', cascade = 'all, delete-orphan', single_parent = True)
Beispiel #23
0
class Library(Entity):
    """"""
    using_options(inheritance='multi')

    # For Movies, CPS uses three: omdbapi (no prio !?), tmdb (prio 2) and couchpotatoapi (prio 1)
    type = Field(String(10), default="movie", index=True)
    primary_provider = Field(String(10), default="imdb", index=True)
    year = Field(Integer)
    identifier = Field(String(40), index=True)

    plot = Field(UnicodeText)
    tagline = Field(UnicodeText(255))
    info = Field(JsonType)

    status = ManyToOne('Status')
    media = OneToMany('Media', cascade='all, delete-orphan')
    titles = OneToMany('LibraryTitle', cascade='all, delete-orphan')
    files = ManyToMany('File',
                       cascade='all, delete-orphan',
                       single_parent=True)

    parent = ManyToOne('Library')
    children = OneToMany('Library')
Beispiel #24
0
class Media(Entity):
    """Media Resource could have multiple releases
    The files belonging to the media object are global for the whole media
    such as trailers, nfo, thumbnails"""

    type = Field(String(10), default="movie", index=True)
    last_edit = Field(Integer, default=lambda: int(time.time()), index=True)

    library = ManyToOne('Library',
                        cascade='delete, delete-orphan',
                        single_parent=True)
    status = ManyToOne('Status')
    profile = ManyToOne('Profile')
    category = ManyToOne('Category')
    releases = OneToMany('Release', cascade='all, delete-orphan')
    files = ManyToMany('File',
                       cascade='all, delete-orphan',
                       single_parent=True)
    class Type(Entity):
        using_options(tablename=type_name.lower(),
                      metadata=metadata,
                      collection=collection)
        __metaclass__ = TypeMeta

        type_description_for = OneToMany(typable_entity)
        description = Field(Unicode(48), required=True)

        class Admin(EntityAdmin):
            verbose_name = typable_entity + ' Type'
            list_display = [
                'description',
            ]
            verbose_name = typable_entity + ' Type'
            if verbose_entity_name is not None:
                verbose_name = verbose_entity_name + ' Type'

        def __unicode__(self):
            return u'Type: %s' % (self.description)
class Party( Entity ):
    """Base class for persons and organizations.  Use this base class to refer to either persons or
    organisations in building authentication systems, contact management or CRM"""
    using_options( tablename = 'party' )

    def __new__(cls, *args, **kwargs):
        party = super(Party, cls).__new__(cls, *args, **kwargs)
        setattr(party, '_contact_mechanisms_email', None)
        setattr(party, '_contact_mechanisms_phone', None)
        return party

    is_synchronized( 'synchronized', lazy = True )
    addresses = OneToMany( 'PartyAddress', lazy = True, cascade="all, delete, delete-orphan" )
    contact_mechanisms = OneToMany( 'PartyContactMechanism', lazy = True, cascade='all, delete, delete-orphan' )
    shares = OneToMany( 'SharedShareholder', inverse = 'established_to', cascade='all, delete, delete-orphan' )
    directed_organizations = OneToMany( 'DirectedDirector', inverse = 'established_to', cascade='all, delete, delete-orphan' )
    status = OneToMany( type_3_status( 'Party', metadata, entities ), cascade='all, delete, delete-orphan' )

    @property
    def name( self ):
        return ''

    @ColumnProperty
    def email( self ):

        cm = ContactMechanism
        pcm = PartyContactMechanism

        return sql.select( [cm.mechanism],
                          whereclause = and_( pcm.table.c.party_id == self.id,
                                              cm.table.c.mechanism.like( ( u'email', u'%' ) ) ),
                          from_obj = [cm.table.join( pcm.table )] ).limit(1)

    @ColumnProperty
    def phone( self ):

        cm = ContactMechanism
        pcm = PartyContactMechanism

        return sql.select( [cm.mechanism],
                          whereclause = and_( pcm.table.c.party_id == self.id,
                                              cm.table.c.mechanism.like( ( u'phone', u'%' ) ) ),
                          from_obj = [cm.table.join( pcm.table )] ).limit(1)

    #
    # Create virtual properties for email and phone that can
    # get and set a contact mechanism for the party
    #
    def _get_contact_mechanisms_email(self):
        return self.email or self._contact_mechanisms_email

    def _set_contact_mechanism_email(self, value):
        # todo : if no value, the existing value should be removed
        if not value or not value[1]:
            return
        self._contact_mechanisms_email = value
        for party_contact_mechanism in self.contact_mechanisms:
            mechanism = party_contact_mechanism.contact_mechanism_mechanism
            if mechanism and mechanism[0] == 'email':
                party_contact_mechanism.contact_mechanism_mechanism = value
                return
        contact_mechanism = ContactMechanism( mechanism = value )
        self.contact_mechanisms.append( PartyContactMechanism(contact_mechanism=contact_mechanism) )

    def _get_contact_mechanisms_phone(self):
        return self.phone or self._contact_mechanisms_phone

    def _set_contact_mechanism_phone(self, value):
        # todo : if no value, the existing value should be removed
        if not value or not value[1]:
            return
        self._contact_mechanisms_phone = value
        for party_contact_mechanism in self.contact_mechanisms:
            mechanism = party_contact_mechanism.contact_mechanism_mechanism
            if mechanism and mechanism[0] == 'phone':
                party_contact_mechanism.contact_mechanism_mechanism = value
                return
        contact_mechanism = ContactMechanism( mechanism = value )
        self.contact_mechanisms.append( PartyContactMechanism(contact_mechanism=contact_mechanism) )

    contact_mechanisms_email = property(_get_contact_mechanisms_email,
                                        _set_contact_mechanism_email)

    contact_mechanisms_phone = property(_get_contact_mechanisms_phone,
                                        _set_contact_mechanism_phone)

    @ColumnProperty
    def full_name( self ):
        aliased_organisation = Organization.table.alias( 'organisation_alias' )
        aliased_person = Person.table.alias( 'person_alias' )
        aliased_party = Party.table.alias( 'party_alias' )
        return sql.functions.coalesce( sql.select( [sql.functions.coalesce(aliased_person.c.first_name,'') + ' ' + sql.functions.coalesce(aliased_person.c.last_name, '')],
                                                  whereclause = and_( aliased_party.c.id == self.id ),
                                                  from_obj = [aliased_party.join( aliased_person, aliased_person.c.party_id == aliased_party.c.id )] ).limit( 1 ).as_scalar(),
                                      sql.select( [aliased_organisation.c.name],
                                                 whereclause = and_( aliased_party.c.id == self.id ),
                                                 from_obj = [aliased_party.join( aliased_organisation, aliased_organisation.c.party_id == aliased_party.c.id )] ).limit( 1 ).as_scalar() )

    class Admin( EntityAdmin ):
        verbose_name = _('Party')
        verbose_name_plural = _('Parties')
        list_display = ['name', 'contact_mechanisms_email', 'contact_mechanisms_phone'] # don't use full name, since it might be None for new objects
        list_search = ['full_name']
        form_display = ['addresses', 'contact_mechanisms', 'shares', 'directed_organizations']
        field_attributes = dict(addresses = {'admin':AddressAdmin},
                                contact_mechanisms = {'admin':PartyPartyContactMechanismAdmin},
                                suppliers = {'admin':SupplierCustomer.SupplierAdmin},
                                customers = {'admin':SupplierCustomer.CustomerAdmin},
                                employers = {'admin':EmployerEmployee.EmployerAdmin},
                                employees = {'admin':EmployerEmployee.EmployeeAdmin},
                                directed_organizations = {'admin':DirectedDirector.DirectedAdmin},
                                directors = {'admin':DirectedDirector.DirectorAdmin},
                                shares = {'admin':SharedShareholder.SharedAdmin},
                                shareholders = {'admin':SharedShareholder.ShareholderAdmin},
                                sex = dict( choices = lambda obj:[( u'M', _('male') ), ( u'F', _('female') )], ),
                                name = dict( minimal_column_width = 50 ),
                                email = dict( editable = False, minimal_column_width = 20 ),
                                phone = dict( editable = False, minimal_column_width = 20 ),
                                contact_mechanisms_email = dict( editable = True,
                                                                 name = _('Email'),
                                                                 address_type = 'email',
                                                                 minimal_column_width = 20,
                                                                 from_string = lambda s:('email', s),
                                                                 delegate = delegates.VirtualAddressDelegate ),
                                contact_mechanisms_phone = dict( editable = True,
                                                                 name = _('Phone'),
                                                                 address_type = 'phone',
                                                                 minimal_column_width = 20,
                                                                 from_string = lambda s:('phone', s),
                                                                 delegate = delegates.VirtualAddressDelegate ),
                                )

        def flush(self, party):
            from sqlalchemy.orm.session import Session
            session = Session.object_session( party )
            if session:
                objects = [ party ]
                for party_contact_mechanism in party.contact_mechanisms:
                    objects.extend([ party_contact_mechanism, party_contact_mechanism.contact_mechanism ])
                session.flush( objects )
                party.expire( ['phone', 'email'] )