Esempio n. 1
0
class Role(dd.Model, Addressable):
    class Meta(object):
        app_label = 'contacts'  # avoid RemovedInDjango19Warning
        abstract = dd.is_abstract_model(__name__, 'Role')
        verbose_name = _("Contact person")
        verbose_name_plural = _("Contact persons")

    type = dd.ForeignKey('contacts.RoleType', blank=True, null=True)
    person = dd.ForeignKey("contacts.Person", related_name='rolesbyperson')
    company = dd.ForeignKey("contacts.Company", related_name='rolesbycompany')

    if with_roles_history:
        start_date = models.DateField(verbose_name=_("Start date"),
                                      blank=True,
                                      null=True)
        end_date = models.DateField(verbose_name=_("End date"),
                                    blank=True,
                                    null=True)
    else:
        start_date = dd.DummyField()
        end_date = dd.DummyField()

    def __str__(self):
        if self.person_id is None:
            return super(Role, self).__str__()
        if self.type is None:
            return str(self.person)
        return "%s (%s)" % (self.person, self.type)

    def address_person_lines(self):
        if self.company:
            for ln in self.company.address_person_lines():
                yield ln
        for ln in self.person.address_person_lines():
            yield ln

    def address_location_lines(self):
        if self.company_id:
            return self.company.address_location_lines()
        if self.person_id:
            return self.person.address_location_lines()
        return super(Role, self).__str__()

    def get_print_language(self):
        if self.company_id:
            return self.company.language
        if self.person_id:
            return self.person.language
        return super(Role, self).get_print_language()

    @dd.chooser()
    def person_choices(cls):
        # needed to activate create_person_choice
        return rt.models.contacts.Person.objects.all()

    def create_person_choice(self, text):
        return rt.models.contacts.Person.create_from_choice(text)
Esempio n. 2
0
class Product(mixins.BabelNamed):
    """A product is something you can sell or buy.

    .. attribute:: description
    .. attribute:: cat
    .. attribute:: delivery_unit

    

    """
    class Meta:
        app_label = 'products'
        verbose_name = _("Product")
        verbose_name_plural = _("Products")
        abstract = dd.is_abstract_model(__name__, 'Product')

    description = dd.BabelTextField(verbose_name=_("Long description"),
                                    blank=True,
                                    null=True)
    cat = models.ForeignKey(ProductCat,
                            verbose_name=_("Category"),
                            blank=True,
                            null=True)

    delivery_unit = DeliveryUnit.field(
        default=DeliveryUnit.piece.as_callable())

    if vat:
        vat_class = vat.VatClasses.field(blank=True)
    else:
        vat_class = dd.DummyField()
Esempio n. 3
0
class Change(dd.Model):
    """A registered change in the database.

    Each database change of a watched object will generate one Change
    record.

    .. attribute:: master

        The database object which acts as "master".
    
    .. attribute:: object

        The database object which has been modified.
    
    
    """
    class Meta(object):
        verbose_name = _("Change")
        verbose_name_plural = _("Changes")

    # allow_cascaded_delete = 'master'
    quick_search_fields = 'changed_fields diff'
    show_in_site_search = False

    time = models.DateTimeField()
    type = ChangeTypes.field()
    if settings.SITE.user_model:
        user = dd.ForeignKey(settings.SITE.user_model)
    else:
        user = dd.DummyField()

    object_type = dd.ForeignKey('contenttypes.ContentType',
                                blank=True,
                                null=True,
                                verbose_name=_("Object type"),
                                related_name='changes_by_object')
    object_id = GenericForeignKeyIdField(object_type, blank=True, null=True)
    object = GenericForeignKey('object_type', 'object_id', _("Object"))

    master_type = dd.ForeignKey('contenttypes.ContentType',
                                blank=True,
                                null=True,
                                verbose_name=_("Master type"),
                                related_name='changes_by_master')
    master_id = GenericForeignKeyIdField(master_type, blank=True, null=True)
    master = GenericForeignKey('master_type', 'master_id', _("Master"))

    diff = dd.RichTextField(_("Changes"),
                            format='plain',
                            blank=True,
                            editable=False)
    changed_fields = dd.CharField(_("Fields"), max_length=250, blank=True)

    def __str__(self):
        # ~ return "#%s - %s" % (self.id,self.time)
        return "#%s" % self.id
Esempio n. 4
0
class Product(mixins.BabelNamed, mixins.Referrable):
    class Meta:
        verbose_name = _("Product")
        verbose_name_plural = _("Products")
        abstract = dd.is_abstract_model(__name__, 'Product')

    description = dd.BabelTextField(verbose_name=_("Long description"),
                                    blank=True,
                                    null=True)
    cat = models.ForeignKey(ProductCat,
                            verbose_name=_("Category"),
                            blank=True,
                            null=True)

    if vat:
        vat_class = vat.VatClasses.field(blank=True)
    else:
        vat_class = dd.DummyField()
Esempio n. 5
0
def inject_partner_field(sender=None, **kwargs):

    User = sender.models.users.User

    if dd.is_installed('contacts'):
        Partner = sender.models.contacts.Partner
        if not issubclass(User, Partner):
            dd.inject_field(
                User, 'partner',
                dd.ForeignKey('contacts.Partner',
                              blank=True,
                              null=True,
                              related_name='users_by_partner',
                              on_delete=models.PROTECT))
            # a related_name is needed so that Avanti can have aClient
            # who inherits from both Partner and UserAuthored
            return
    dd.inject_field(User, 'partner', dd.DummyField())
Esempio n. 6
0
class LanguageKnowledge(dd.Model):
    class Meta:
        abstract = dd.is_abstract_model(__name__, 'LanguageKnowledge')
        app_label = 'cv'
        verbose_name = _("Language knowledge")
        verbose_name_plural = _("Language knowledges")
        unique_together = ['person', 'language', 'entry_date'] \
            if config.with_language_history else ['person', 'language']
        ordering = ['-entry_date', '-id'] \
            if config.with_language_history else ['id']

    allow_cascaded_delete = ['person']

    person = dd.ForeignKey(config.person_model)
    language = dd.ForeignKey("languages.Language")
    spoken = HowWell.field(_("Spoken"), blank=True)
    written = HowWell.field(_("Written"), blank=True)
    spoken_passively = HowWell.field(_("Spoken (passively)"), blank=True)
    written_passively = HowWell.field(_("Written (passively)"), blank=True)
    native = models.BooleanField(_("Mother tongue"), default=False)
    cef_level = CefLevel.field(blank=True)  # ,null=True)
    has_certificate = models.BooleanField(_("Certificate"), default=False)

    if config.with_language_history:
        entry_date = models.DateField(_("Entry date"), default=dd.today)
    else:
        entry_date = dd.DummyField()

    def __str__(self):
        if self.language_id is None:
            return ''
        if self.native:
            return _("%s (MT)") % (self.language)
        if self.cef_level:
            return u"%s (%s)" % (self.language, self.cef_level)
        if self.spoken:
            if self.written:
                return _(u"%s (s/w)") % self.language
            else:
                return _(u"%s (s)") % self.language
        elif self.written:
            return _(u"%s (w)") % self.language
        else:
            return str(self.language)
Esempio n. 7
0
class TimezoneHolder(models.Model):
    """Mixin for database models which have a :attr:`timezone` field.

    .. attribute:: timezone
    
        The timezone.

    """
    class Meta(object):
        abstract = True

    if settings.USE_TZ:
        timezone = models.CharField(_("Time zone"), max_length=15, blank=True)
    else:
        timezone = dd.DummyField()

    @dd.chooser(simple_values=True)
    def timezone_choices(cls, partner):
        import pytz
        if partner and partner.country:
            return pytz.country_timezones[partner.country.isocode]
        return pytz.common_timezones
Esempio n. 8
0
class User(CreatedModified):
    """Represents a user of this site.

    .. attribute:: username
    
        The primary key.

    .. attribute:: profile

        The profile of a user is what defines her or his permissions.

        Users with an empty `profile` field are considered inactive and
        cannot log in.


    .. attribute:: partner

        Pointer to the :class:`lino.modlib.contacts.models.Partner`
        instance related to this user.

        This is a DummyField when :mod:`lino.modlib.contacts` is not
        installed.

    """
    class Meta:
        verbose_name = _('User')
        verbose_name_plural = _('Users')
        abstract = dd.is_abstract_model(__name__, 'User')
        ordering = ['last_name', 'first_name', 'username']

    preferred_foreignkey_width = 15

    hidden_columns = 'password remarks'

    authenticated = True
    """This is always `True`.
    See also :attr:`lino.modlib.users.utils.AnonymousUser.authenticated`.
    """

    username = models.CharField(_('Username'),
                                max_length=30,
                                unique=True,
                                help_text=_("""Required. Must be unique."""))

    password = models.CharField(_('Password'), max_length=128)

    profile = UserProfiles.field(
        blank=True,
        help_text=_("Users with an empty `profile` field are considered "
                    "inactive and cannot log in."))

    initials = models.CharField(_('Initials'), max_length=10, blank=True)
    first_name = models.CharField(_('First name'), max_length=30, blank=True)
    last_name = models.CharField(_('Last name'), max_length=30, blank=True)
    email = models.EmailField(_('e-mail address'), blank=True)

    remarks = models.TextField(_("Remarks"), blank=True)  # ,null=True)

    language = dd.LanguageField(default=models.NOT_PROVIDED, blank=True)

    if dd.is_installed('contacts'):

        partner = models.ForeignKey('contacts.Partner',
                                    blank=True,
                                    null=True,
                                    on_delete=models.PROTECT)

    else:

        partner = dd.DummyField()

    def __unicode__(self):
        return self.get_full_name()

    def get_full_name(self):
        "Returns the first_name plus the last_name, with a space in between."
        if not self.first_name and not self.last_name:
            return self.username
        return u'%s %s' % (self.first_name.strip(), self.last_name.strip())

    @dd.displayfield(_("Name"), max_length=15)
    def name_column(self, request):
        #~ return join_words(self.last_name.upper(),self.first_name)
        return unicode(self)

    if dd.is_installed('contacts'):

        def get_person(self):
            if self.partner:
                return self.partner.get_mti_child('person')
    else:

        def get_person(self):
            return None

    person = property(get_person)

    def get_row_permission(self, ar, state, ba):
        """
        Only system managers may edit other users.
        See also :meth:`User.disabled_fields`.
        """
        #~ print 20120621, self, user, state, action
        if not ba.action.readonly:
            user = ar.get_user()
            if user != self:
                if not isinstance(user.profile.role, dd.SiteAdmin):
                    return False
        return super(User, self).get_row_permission(ar, state, ba)
        #~ return False

    def disabled_fields(self, ar):
        """
        Only System admins may change the `profile` of users.
        See also :meth:`Users.get_row_permission`.
        """
        rv = super(User, self).disabled_fields(ar)
        if not isinstance(ar.get_user().profile.role, dd.SiteAdmin):
            rv.add('profile')
        return rv

    def full_clean(self, *args, **kw):
        p = self.person
        if p is not None:
            for n in ('first_name', 'last_name', 'email', 'language'):
                if not getattr(self, n):
                    setattr(self, n, getattr(p, n))
            #~ self.language = p.language
        if not self.language:
            #~ self.language = settings.SITE.DEFAULT_LANGUAGE.django_code
            self.language = settings.SITE.get_default_language()
        if not self.password:
            self.set_unusable_password()
        if not self.initials:
            if self.first_name and self.last_name:
                self.initials = self.first_name[0] + self.last_name[0]
        super(User, self).full_clean(*args, **kw)

    def get_received_mandates(self):
        #~ return [ [u.id,_("as %s")%u] for u in self.__class__.objects.all()]
        return [[u.id, unicode(u)] for u in self.__class__.objects.all()]
        #~ return self.__class__.objects.all()

    change_password = ChangePassword()

    # the following methods are unchanged copies from Django's User
    # model

    def set_password(self, raw_password):
        self.password = make_password(raw_password)

    def check_password(self, raw_password):
        """
        Returns a boolean of whether the raw_password was correct. Handles
        hashing formats behind the scenes.
        """
        def setter(raw_password):
            self.set_password(raw_password)
            self.save()

        return check_password(raw_password, self.password, setter)

    def set_unusable_password(self):
        # Sets a value that will never be a valid hash
        self.password = make_password(None)

    def has_usable_password(self):
        return is_password_usable(self.password)

    def as_list_item(self, ar):
        return E.li(E.strong(self.username), ' : ', unicode(self), ', ',
                    unicode(self.profile), ', ',
                    E.strong(settings.SITE.LANGUAGE_DICT.get(self.language)))

    @classmethod
    def get_by_username(cls, username, default=models.NOT_PROVIDED):
        """
        `User.get_by_username(x)` is equivalent to
        `User.objects.get(username=x)` except that the text 
        of the DoesNotExist exception is more useful.
        """
        try:
            return cls.objects.get(username=username)
        except cls.DoesNotExist:
            if default is models.NOT_PROVIDED:
                raise cls.DoesNotExist(
                    "No %s with username %r" %
                    (unicode(cls._meta.verbose_name), username))
            return default
Esempio n. 9
0
class Role(dd.Model, Addressable):
    class Meta(object):
        app_label = 'contacts'  # avoid RemovedInDjango19Warning
        abstract = dd.is_abstract_model(__name__, 'Role')
        verbose_name = _("Contact Person")
        verbose_name_plural = _("Contact Persons")

    type = dd.ForeignKey('contacts.RoleType', blank=True, null=True)
    person = dd.ForeignKey("contacts.Person", related_name='rolesbyperson')
    company = dd.ForeignKey("contacts.Company", related_name='rolesbycompany')

    if with_roles_history:
        start_date = models.DateField(verbose_name=_("Start date"),
                                      blank=True,
                                      null=True)
        end_date = models.DateField(verbose_name=_("End date"),
                                    blank=True,
                                    null=True)
    else:
        start_date = dd.DummyField()
        end_date = dd.DummyField()

    def __str__(self):
        if self.person_id is None:
            return super(Role, self).__str__()
        if self.type is None:
            return str(self.person)
        return u"%s (%s)" % (self.person, self.type)

    def address_person_lines(self):
        if self.company:
            for ln in self.company.address_person_lines():
                yield ln
        for ln in self.person.address_person_lines():
            yield ln

    def address_location_lines(self):
        if self.company_id:
            return self.company.address_location_lines()
        if self.person_id:
            return self.person.address_location_lines()
        return super(Role, self).__str__()

    def get_print_language(self):
        if self.company_id:
            return self.company.language
        if self.person_id:
            return self.person.language
        return super(Role, self).get_print_language()

    @dd.chooser()
    def person_choices(cls):
        # needed to activate create_person_choice
        return rt.models.contacts.Person.objects.all()

    def create_person_choice(self, text):
        """
        Called when an unknown person name was given.
        If the given text looks like a full name of a person, create it.
        """
        person_model = rt.models.contacts.Person
        if person_model.disable_create_choice:
            return
        try:
            values = person_model.parse_to_dict(text)
        except Exception as e:
            raise ValidationError(
                _("Could not create {person} from '{text}'").format(
                    person=person_model._meta.verbose_name, text=text))
        obj = person_model(**values)
        obj.full_clean()
        obj.save()
        return obj
Esempio n. 10
0
class User(AbstractBaseUser, Contactable, CreatedModified, DateRange,
           Printable):
    class Meta(object):
        app_label = 'users'
        verbose_name = _('User')
        verbose_name_plural = _('Users')
        abstract = dd.is_abstract_model(__name__, 'User')
        ordering = ['last_name', 'first_name', 'username']

    USERNAME_FIELD = 'username'
    _anon_user = None
    objects = UserManager()

    preferred_foreignkey_width = 15
    hidden_columns = 'password remarks'
    authenticated = True
    quick_search_fields = 'username user_type first_name last_name remarks'

    # seems that Django doesn't like nullable username
    # username = dd.NullCharField(_('Username'), max_length=30, unique=True)
    username = models.CharField(_('Username'), max_length=30, unique=True)

    user_type = UserTypes.field(blank=True)
    initials = models.CharField(_('Initials'), max_length=10, blank=True)
    first_name = models.CharField(_('First name'), max_length=30, blank=True)
    last_name = models.CharField(_('Last name'), max_length=30, blank=True)
    remarks = models.TextField(_("Remarks"), blank=True)  # ,null=True)

    if settings.USE_TZ:
        time_zone = TimeZones.field(default='default')
    else:
        time_zone = dd.DummyField()

    change_password = ChangePassword()
    # sign_in = SignIn()
    sign_out = SignOut()

    def __str__(self):
        return self.get_full_name()

    @property
    def is_active(self):
        if self.start_date and self.start_date > dd.today():
            return False
        if self.end_date and self.end_date < dd.today():
            return False
        return True

    def get_as_user(self):
        """
        Overrides :meth:`lino_xl.lib.contacts.Partner.get_as_user`.
        """
        return self

    def get_full_name(self):
        if not self.first_name and not self.last_name:
            return self.initials or self.username or str(self.pk)
        return u'{} {}'.format(self.first_name, self.last_name).strip()

    @dd.displayfield(_("Name"), max_length=15)
    def name_column(self, request):
        # return join_words(self.last_name.upper(),self.first_name)
        return str(self)

    # @dd.displayfield(_("Other authentication providers"))
    # def social_auth_links(self, ar=None):
    #     return settings.SITE.get_social_auth_links        ()
    #     # elems = []
    #     # for backend in get_social_auth_backends()
    #     # elems.append(E.a("foo"))
    #     # return E.p(elems)

    def get_person(self):
        if self.partner:
            return self.partner.get_mti_child('person')

    person = property(get_person)

    def is_editable_by_all(self):
        return False

    def get_row_permission(self, ar, state, ba):
        #~ print 20120621, self, user, state, action
        # import pdb ; pdb.set_trace()
        if not ba.action.readonly:
            user = ar.get_user()
            if user != self:
                if not user.user_type.has_required_roles([SiteAdmin]):
                    if not self.is_editable_by_all():
                        return False
        return super(User, self).get_row_permission(ar, state, ba)
        #~ return False

    def disabled_fields(self, ar):
        """
        Only System admins may change the `user_type` of users.
        See also :meth:`Users.get_row_permission`.
        """
        rv = super(User, self).disabled_fields(ar)
        user = ar.get_user()
        if not user.user_type.has_required_roles([SiteAdmin]):
            rv.add('send_email')
            rv.add('user_type')
            if user != self:
                rv.add('change_password')
        return rv

    def full_clean(self, *args, **kw):
        p = self.get_person()
        if p is not None and p != self:
            for n in ('first_name', 'last_name', 'email', 'language'):
                if not getattr(self, n):
                    setattr(self, n, getattr(p, n))
            #~ self.language = p.language
        if not self.language:
            #~ self.language = settings.SITE.DEFAULT_LANGUAGE.django_code
            self.language = settings.SITE.get_default_language()
        if not self.password:
            self.set_unusable_password()
        # if not self.initials:
        #     if self.first_name and self.last_name:
        #         self.initials = self.first_name[0] + self.last_name[0]
        super(User, self).full_clean(*args, **kw)

    def on_create(self, ar):
        self.start_date = dd.today()
        super(User, self).on_create(ar)

    def get_received_mandates(self):
        #~ return [ [u.id,_("as %s")%u] for u in self.__class__.objects.all()]
        return [[u.id, str(u)] for u in self.__class__.objects.all()]
        #~ return self.__class__.objects.all()

    # @dd.htmlbox(_("Welcome"))
    # def welcome_email_body(self, ar):
    #     # return join_words(self.last_name.upper(),self.first_name)
    #     return self.get_welcome_email_body(ar)

    def get_welcome_email_body(self, ar):
        template = rt.get_template('users/welcome_email.eml')
        context = self.get_printable_context(ar)
        # dict(obj=self, E=E, rt=rt)
        return template.render(**context)

    def as_list_item(self, ar):
        pv = dict(username=self.username)
        if settings.SITE.is_demo_site:
            pv.update(password='******')
        btn = rt.models.users.UsersOverview.get_action_by_name('sign_in')
        # print btn.get_row_permission(ar, None, None)
        btn = btn.request(action_param_values=pv,
                          renderer=settings.SITE.kernel.default_renderer)
        btn = btn.ar2button(label=self.username)
        items = [btn, ' : ', str(self), ', ', str(self.user_type)]
        if self.language:
            items += [
                ', ',
                E.strong(str(settings.SITE.LANGUAGE_DICT.get(self.language)))
            ]
        return E.li(*items)
        # if settings.SITE.is_demo_site:
        #     p = "'{0}', '{1}'".format(self.username, '1234')
        # else:
        #     p = "'{0}'".format(self.username)
        # url = "javascript:Lino.show_login_window(null, {0})".format(p)
        # return E.li(E.a(self.username, href=url), ' : ',
        #             str(self), ', ',
        #             str(self.user_type), ', ',
        #             E.strong(settings.SITE.LANGUAGE_DICT.get(self.language)))

    @classmethod
    def get_by_username(cls, username, default=models.NOT_PROVIDED):
        """
        `User.get_by_username(x)` is equivalent to
        `User.objects.get(username=x)` except that the text of the
        DoesNotExist exception is more useful.
        """
        try:
            return cls.objects.get(username=username)
        except cls.DoesNotExist:
            if default is models.NOT_PROVIDED:
                raise cls.DoesNotExist("No %s with username %r" %
                                       (str(cls._meta.verbose_name), username))
            return default

    def get_preferences(self):
        """
        Return the preferences of this user. The returned object is a
        :class:`lino.core.userprefs.UserPrefs` object.
        """
        return userprefs.reg.get(self)

    @classmethod
    def get_anonymous_user(cls):
        return AnonymousUser()
Esempio n. 11
0
class MailableType(dd.Model):
    email_template = dd.DummyField()
    attach_to_email = dd.DummyField()

    class Meta:
        abstract = True
Esempio n. 12
0
# -*- coding: UTF-8 -*-
# Copyright 2012-2014 Luc Saffre
#
# License: BSD (see file COPYING for details)
"""
The :term:`dummy module` for `outbox`, 
used by :func:`lino.core.utils.resolve_app`.
"""
from lino.api import dd


class Mailable(object):
    pass


#~ class MailableType(object): pass


class MailableType(dd.Model):
    email_template = dd.DummyField()
    attach_to_email = dd.DummyField()

    class Meta:
        abstract = True


MailsByController = dd.DummyField()
Esempio n. 13
0
class Session(UserAuthored, Started, Ended, Workable):
    class Meta:
        app_label = 'working'
        verbose_name = _("Session")
        verbose_name_plural = _('Sessions')
        abstract = dd.is_abstract_model(__name__, 'Session')

    ticket = dd.ForeignKey(dd.plugins.working.ticket_model,
                           related_name="sessions_by_ticket")

    session_type = dd.ForeignKey('working.SessionType', null=True, blank=True)
    summary = models.CharField(_("Summary"),
                               max_length=200,
                               blank=True,
                               help_text=_("Summary of the session."))
    description = dd.RichTextField(_("Description"), blank=True)
    # break_time = models.TimeField(
    #     blank=True, null=True,
    #     verbose_name=_("Break Time"))
    break_time = dd.DurationField(_("Break Time"), blank=True, null=True)
    faculty = dd.ForeignKey('skills.Skill',
                            related_name="sessions_by_faculty",
                            blank=True,
                            null=True)

    reporting_type = ReportingTypes.field(blank=True)
    is_fixing = models.BooleanField(_("Fixing"), default=False)
    if settings.USE_TZ:
        time_zone = TimeZones.field()
    else:
        time_zone = dd.DummyField()

    end_session = EndThisSession()
    show_today = ShowMySessionsByDay('start_date')

    # print_activity_report = PrintActivityReport()

    def __str__(self):
        if self.start_time and self.end_time:
            return u"%s %s-%s" % (
                self.start_date.strftime(settings.SITE.date_format_strftime),
                self.start_time.strftime(settings.SITE.time_format_strftime),
                self.end_time.strftime(settings.SITE.time_format_strftime))
        return "%s # %s" % (self._meta.verbose_name, self.pk)

    def get_ticket(self):
        return self.ticket

    def on_create(self, ar):
        super(Session, self).on_create(ar)
        if settings.USE_TZ:
            self.time_zone = self.user.time_zone or \
                             rt.models.about.TimeZones.default

    def get_time_zone(self):
        return self.time_zone

    def full_clean(self, *args, **kwargs):
        if self.user_id and not self.time_zone:
            # can be removed when all production sites have migrated:
            self.time_zone = self.user.time_zone or \
                             rt.models.about.TimeZones.default

        if not settings.SITE.loading_from_dump:
            if self.start_time is None:
                self.set_datetime('start', timezone.now())
                # value = timezone.now()
                # if pytz:
                #     tz = pytz.timezone(self.get_timezone())
                #     value = value.astimezone(tz)
                # self.start_time = value.time()
            if self.start_date is None:
                self.start_date = dd.today()
            # if self.ticket_id is not None and self.faculty_id is None:
            #     self.faculty = self.ticket.faculty
            if self.end_time is not None:
                if self.end_date is None:
                    self.end_date = self.start_date
            if self.ticket_id:
                self.ticket.on_worked(self)

        super(Session, self).full_clean(*args, **kwargs)

    def unused_save(self, *args, **kwargs):
        if not settings.SITE.loading_from_dump:
            if self.start_date is None:
                self.start_date = dd.today()
            if self.start_time is None:
                self.start_time = timezone.now().time()
        super(Session, self).save(*args, **kwargs)

    def get_reporting_type(self):
        if self.reporting_type:
            return self.reporting_type
        t = self.get_ticket()
        if t.ticket_type and t.ticket_type.reporting_type:
            return t.ticket_type.reporting_type
        if t.site and t.site.reporting_type:
            return t.site.reporting_type
        # if t.project and t.project.reporting_type:
        #     return t.project.reporting_type
        return dd.plugins.working.default_reporting_type

    # def after_ui_save(self, ar, cw):
    #     super(Session, self).after_ui_save(ar, cw)
    #     if self.ticket_id:
    #         self.ticket.on_worked(self, ar, cw)

    def get_root_project(self):
        """Return the root project for this session (or None if session has no
        ticket).

        """
        if self.ticket and self.ticket.project:
            return self.ticket.project.get_parental_line()[0]

    def get_duration(self):
        """Return the duration in hours as a
        :class:`lino.utils.quantities.Quantity`.  This inherits from
        :meth:`StartedEnded
        <lino_xl.lib.cal.mixins.StartedEnded.get_duration>` but
        removes :attr:`break_time` if specified.

        """
        diff = super(Session, self).get_duration()
        if diff and self.break_time:
            diff -= self.break_time
        return diff

        # if self.end_time is None:
        #     diff = datetime.timedelta()
        # else:
        #     diff = self.get_datetime('end') - self.get_datetime('start')
        #     if self.break_time is not None:
        #         diff -= self.break_time
        # return Duration(diff)

    @dd.displayfield(_("Ticket #"))
    def ticket_no(self, ar):
        if ar is None:
            return self.ticket_id
        return self.ticket.obj2href(ar)  # self.ticket_id)

    @dd.displayfield(_("Site"))
    def site_ref(self, ar):
        if not self.ticket:
            return ''
        site = self.ticket.site
        if site is None:
            return ''
        if ar is None:
            return str(site)
        return site.obj2href(ar)
Esempio n. 14
0
    ("theme-crisp", "Theme Crisp"),
    ("theme-crisp-touch", "Theme crisp touch"),
    ("theme-gray", "Theme gray"),
    ("theme-neptune", "Theme neptune"),
    ("theme-neptune-touch", "Theme neptune touch"),
    ("theme-triton", "Theme triton"),
)

if dd.plugins.extjs.select_theme:
    dd.inject_field(
        'users.User', 'preferred_theme',
        models.CharField(_("Preferred theme"),
                         choices=EXTJS6_THEMES_CHOICES,
                         default="",
                         blank=True,
                         max_length=25))
else:
    dd.inject_field('users.User', 'preferred_theme', dd.DummyField())


class ThemedUserDetail(UserDetail):
    box1 = """
        username user_type:20 partner
        first_name last_name initials
        email language time_zone preferred_theme
        id created modified
        """


Users.set_detail_layout(ThemedUserDetail())
Esempio n. 15
0
class User(AbstractBaseUser, Contactable, CreatedModified, TimezoneHolder):
    """Represents a user of this site.

    .. attribute:: username
    
        Must be unique.
        Leaving this empty means that the user cannot log in.

    .. attribute:: profile

        The profile of a user is what defines her or his permissions.

        Users with an empty `profile` field are considered inactive and
        cannot log in.


    .. attribute:: partner

        Pointer to the :class:`Partner
        <lino_xl.lib.contacts.models.Partner>` instance related to
        this user.

        This is a DummyField when :mod:`lino_xl.lib.contacts` is not
        installed.

    .. attribute:: person

        A virtual read-only field which returns the :class:`Person
        <lino_xl.lib.contacts.models.Person>` MTI child corresponding
        to the :attr:`partner` (if it exists) and otherwise `None`.

    .. attribute:: last_login

        Not used in Lino.
    
    """
    class Meta(object):
        app_label = 'users'
        verbose_name = _('User')
        verbose_name_plural = _('Users')
        abstract = dd.is_abstract_model(__name__, 'User')
        ordering = ['last_name', 'first_name', 'username']

    USERNAME_FIELD = 'username'

    preferred_foreignkey_width = 15

    hidden_columns = 'password remarks'

    authenticated = True
    """This is always `True`.
    See also :attr:`lino.modlib.users.utils.AnonymousUser.authenticated`.
    """

    username = NullCharField(
        _('Username'),
        max_length=30,
        unique=True,
        help_text=_("Must be unique. "
                    "Leaving this empty means that the user cannot log in."))

    profile = UserTypes.field(blank=True)

    initials = models.CharField(_('Initials'), max_length=10, blank=True)
    first_name = models.CharField(_('First name'), max_length=30, blank=True)
    last_name = models.CharField(_('Last name'), max_length=30, blank=True)
    remarks = models.TextField(_("Remarks"), blank=True)  # ,null=True)

    if dd.is_installed('contacts'):

        partner = models.ForeignKey('contacts.Partner',
                                    blank=True,
                                    null=True,
                                    on_delete=models.PROTECT)

    else:

        partner = dd.DummyField()

    change_password = ChangePassword()

    def __str__(self):
        return self.get_full_name()

    def get_full_name(self):
        "Returns the first_name plus the last_name, with a space in between."
        if not self.first_name and not self.last_name:
            return self.username
        return u'{} {}'.format(self.first_name, self.last_name).strip()

    @dd.displayfield(_("Name"), max_length=15)
    def name_column(self, request):
        # return join_words(self.last_name.upper(),self.first_name)
        return str(self)

    if dd.is_installed('contacts'):

        def get_person(self):
            if self.partner:
                return self.partner.get_mti_child('person')
    else:

        def get_person(self):
            return None

    person = property(get_person)

    def is_editable_by_all(self):
        return False

    def get_row_permission(self, ar, state, ba):
        """Only system managers may edit other users.
        See also :meth:`User.disabled_fields`.

        One exception is when AnonymousUser is not readonly. This
        means that we want to enable online registration. In this case
        everybody can modify an unsaved user.

        """
        #~ print 20120621, self, user, state, action
        # import pdb ; pdb.set_trace()
        if not ba.action.readonly:
            user = ar.get_user()
            if user != self:
                if not user.profile.has_required_roles([SiteAdmin]):
                    if not self.is_editable_by_all():
                        return False
        return super(User, self).get_row_permission(ar, state, ba)
        #~ return False

    def disabled_fields(self, ar):
        """
        Only System admins may change the `profile` of users.
        See also :meth:`Users.get_row_permission`.
        """
        rv = super(User, self).disabled_fields(ar)
        if not ar.get_user().profile.has_required_roles([SiteAdmin]):
            rv.add('profile')
        return rv

    def full_clean(self, *args, **kw):
        p = self.person
        if p is not None:
            for n in ('first_name', 'last_name', 'email', 'language'):
                if not getattr(self, n):
                    setattr(self, n, getattr(p, n))
            #~ self.language = p.language
        if not self.language:
            #~ self.language = settings.SITE.DEFAULT_LANGUAGE.django_code
            self.language = settings.SITE.get_default_language()
        if not self.password:
            self.set_unusable_password()
        if not self.initials:
            if self.first_name and self.last_name:
                self.initials = self.first_name[0] + self.last_name[0]
        super(User, self).full_clean(*args, **kw)

    def get_received_mandates(self):
        #~ return [ [u.id,_("as %s")%u] for u in self.__class__.objects.all()]
        return [[u.id, str(u)] for u in self.__class__.objects.all()]
        #~ return self.__class__.objects.all()

    # @dd.htmlbox(_("Welcome"))
    # def welcome_email_body(self, ar):
    #     # return join_words(self.last_name.upper(),self.first_name)
    #     return self.get_welcome_email_body(ar)

    def get_welcome_email_body(self, ar):
        template = rt.get_template('users/welcome_email.eml')
        context = self.get_printable_context(ar)
        # dict(obj=self, E=E, rt=rt)
        return template.render(**context)

    def as_list_item(self, ar):
        if settings.SITE.is_demo_site:
            p = "'{0}', '{1}'".format(self.username, '1234')
        else:
            p = "'{0}'".format(self.username)
        url = "javascript:Lino.show_login_window(null, {0})".format(p)
        return E.li(E.a(self.username, href=url), ' : ', str(self), ', ',
                    str(self.profile), ', ',
                    E.strong(settings.SITE.LANGUAGE_DICT.get(self.language)))

    @classmethod
    def get_by_username(cls, username, default=models.NOT_PROVIDED):
        """
        `User.get_by_username(x)` is equivalent to
        `User.objects.get(username=x)` except that the text
        of the DoesNotExist exception is more useful.
        """
        try:
            return cls.objects.get(username=username)
        except cls.DoesNotExist:
            if default is models.NOT_PROVIDED:
                raise cls.DoesNotExist("No %s with username %r" %
                                       (str(cls._meta.verbose_name), username))
            return default

    def get_preferences(self):
        """Return the preferences of this user. The returned object is a
        :class:`lino.core.userprefs.UserPrefs` object.

        """
        return userprefs.reg.get(self)