示例#1
0
文件: models.py 项目: zyrobin/lino
class TextFieldTemplate(UserAuthored):
    """A reusable block of text that can be selected from a text editor to
    be inserted into the text being edited.

    """
    class Meta(object):
        verbose_name = _("Text Field Template")
        verbose_name_plural = _("Text Field Templates")

    name = models.CharField(_("Designation"), max_length=200)
    description = dd.RichTextField(_("Description"),
                                   blank=True,
                                   null=True,
                                   format='plain')
    #~ blank=True,null=True,format='html')
    # team = dd.ForeignKey(
    #     'users.Team', blank=True, null=True,
    #     help_text=_("If not empty, then this template "
    #                 "is reserved to members of this team."))
    text = dd.RichTextField(_("Template Text"),
                            blank=True,
                            null=True,
                            format='html')

    def __str__(self):
        return self.name
示例#2
0
文件: models.py 项目: DarioGT/lino
class Comment(
        mixins.CreatedModified,
        UserAuthored,
        # mixins.Hierarchical,
        Controllable):
    """A **comment** is a short text which some user writes about some
    other database object.

    .. attribute:: short_text

        A short "abstract" of your comment. This should not be more
        than one paragraph.

    """

    ALLOWED_TAGS = ['a', 'b', 'i', 'em']

    class Meta:
        abstract = dd.is_abstract_model(__name__, 'Comment')
        verbose_name = _("Comment")
        verbose_name_plural = _("Comments")

    short_text = dd.RichTextField(_("Short text"))
    more_text = dd.RichTextField(_("More text"), blank=True)

    def __unicode__(self):
        return u'%s #%s' % (self._meta.verbose_name, self.pk)

    def as_li(self, ar):
        """Return this comment as a list item. If `bleach
        <http://bleach.readthedocs.org/en/latest/>`_ is installed, all
        tags except some will be removed when

        """
        if bleach is None:
            chunks = [self.short_text]
        else:
            chunks = [bleach.clean(
                self.short_text, tags=self.ALLOWED_TAGS, strip=True)]

        by = _("{0} by {1}").format(
            naturaltime(self.created), unicode(self.user)),
        chunks += [
            " (", E.tostring(ar.obj2html(self, by)), ")"
        ]
        if self.more_text:
            chunks.append(" (...)")

        html = ''.join(chunks)
        return "<li>" + html + "</li>"
示例#3
0
文件: models.py 项目: DarioGT/lino
class RecurrentEvent(mixins.BabelNamed, RecurrenceSet, EventGenerator):
    """An event that recurs at intervals.
    """
    class Meta:
        app_label = 'cal'
        verbose_name = _("Recurrent Event")
        verbose_name_plural = _("Recurrent Events")

    event_type = models.ForeignKey('cal.EventType', blank=True, null=True)
    description = dd.RichTextField(_("Description"), blank=True, format='html')

    def before_auto_event_save(self, obj):
        if self.end_date and self.end_date != self.start_date:
            duration = self.end_date - self.start_date
            obj.end_date = obj.start_date + duration
        super(RecurrentEvent, self).before_auto_event_save(obj)

    #~ def on_create(self,ar):
    #~ super(RecurrentEvent,self).on_create(ar)
    #~ self.event_type = settings.SITE.site_config.holiday_event_type

    #~ def __unicode__(self):
    #~ return self.summary

    def update_cal_rset(self):
        return self

    def update_cal_from(self, ar):
        return self.start_date

    def update_cal_calendar(self):
        return self.event_type

    def update_cal_summary(self, i):
        return unicode(self)
示例#4
0
class Item(mixins.Sequenced):
    class Meta:
        verbose_name = _("Import Filter Item")
        verbose_name_plural = _("Import Filter Items")

    filter = dd.ForeignKey(Filter)
    field = models.CharField(_("Field"), max_length=200)
    column = models.IntegerField(_("Column"))

    help_text = dd.RichTextField(_("HelpText"),
                                 blank=True,
                                 null=True,
                                 format='plain')

    @dd.chooser(simple_values=True)
    def field_choices(cls, filter):
        l = []
        if filter is not None:
            model = filter.content_type.model_class()
            meta = model._meta
            for f in meta.fields:
                if not getattr(f, '_lino_babel_field', False):
                    l.append(f.name)
            l.sort()
        return l
示例#5
0
class Entry(UserAuthored, Controllable, CombinedDateTime):
    """A blog entry is a short article with a title, published on a given
    date and time by a given user.

    """
    class Meta:
        app_label = 'blogs'
        verbose_name = _("Blog Entry")
        verbose_name_plural = _("Blog Entries")

    title = models.CharField(_("Heading"), max_length=200, blank=True)
    body = dd.RichTextField(_("Body"), blank=True, format='html')

    pub_date = models.DateField(_("Publication date"), blank=True, null=True)
    pub_time = models.TimeField(_("Publication time"), blank=True, null=True)

    entry_type = dd.ForeignKey('blogs.EntryType', blank=True, null=True)

    language = dd.LanguageField()

    def __str__(self):
        return u'%s #%s' % (self._meta.verbose_name, self.pk)

    def on_create(self, ar):
        """
        Sets the :attr:`pub_date` and :attr:`pub_time` to now.

        """
        if not settings.SITE.loading_from_dump:
            self.set_datetime('pub', timezone.now())
            self.language = ar.get_user().language
        super(Entry, self).on_create(ar)
示例#6
0
class Import(dd.VirtualTable):
    column_names = 'description obj2unicode'
    parameters = dict(filter=dd.ForeignKey(Filter),
                      data=dd.RichTextField(_("Data to import"),
                                            blank=True,
                                            null=True,
                                            format='plain'))

    @classmethod
    def get_data_rows(self, ar):
        flt = ar.param_values.filter
        build = Instantiator(flt.content_type.model_class()).build
        for ln in ar.param_values.data.splitlines():
            ln = ln.strip()
            if ln:
                kw = dict()
                cells = flt.field_sep.split(ln)
                for item in flt.item_set.all():
                    if item.column:
                        kw[item.field] = cells[item.column - 1]
                yield build(**kw)

    @dd.displayfield(_("Description"))
    def description(cls, obj, ar):
        kw = dict()
        flt = ar.param_values.filter
        for item in flt.item_set.all():
            kw[item.field] = getattr(obj, item.field)
        return unicode(kw)

    @dd.displayfield(_("obj2unicode"))
    def obj2unicode(cls, obj, ar):
        return dd.obj2unicode(obj)
示例#7
0
class StartedSummaryDescription(Started):

    """
    """

    class Meta:
        abstract = True

    # iCal:SUMMARY
    summary = models.CharField(_("Summary"), max_length=200, blank=True)
    description = dd.RichTextField(
        _("Description"),
        blank=True,
        format='plain')
        # format='html')

    def __unicode__(self):
        return self._meta.verbose_name + " #" + str(self.pk)

    def summary_row(self, ar, **kw):
        elems = list(super(StartedSummaryDescription, self)
                     .summary_row(ar, **kw))

        if self.summary:
            elems.append(': %s' % self.summary)
        elems += [_(" on "), dd.dtos(self.start_date)]
        return elems
示例#8
0
class RecurrentEvent(mixins.BabelNamed, RecurrenceSet, EventGenerator,
                     UserAuthored):
    class Meta:
        app_label = 'cal'
        verbose_name = _("Recurring event")
        verbose_name_plural = _("Recurring events")
        abstract = dd.is_abstract_model(__name__, 'RecurrentEvent')

    event_type = dd.ForeignKey('cal.EventType', blank=True, null=True)
    description = dd.RichTextField(
        _("Description"), blank=True, format='html')

    # def on_create(self,ar):
        # super(RecurrentEvent,self).on_create(ar)
        # self.event_type = settings.SITE.site_config.holiday_event_type

    # def __unicode__(self):
        # return self.summary

    def update_cal_rset(self):
        return self

    def update_cal_from(self, ar):
        return self.start_date

    def update_cal_event_type(self):
        return self.event_type

    def update_cal_summary(self, et, i):
        return str(self)

    def care_about_conflicts(self, we):
        return False
示例#9
0
文件: models.py 项目: TonisPiip/xl
class Note(TypedPrintable, UserAuthored, Controllable, ContactRelated,
           mixins.ProjectRelated, Mailable):
    """A **note** is a dated and timed document written by its author (a
    user). For example a report of a meeting or a phone call, or just
    some observation. Notes are usually meant for internal use.

    .. attribute:: date
    .. attribute:: time
    .. attribute:: type
    .. attribute:: event_type
    .. attribute:: subject
    .. attribute:: body
    .. attribute:: language


    """

    manager_roles_required = dd.login_required(OfficeStaff)

    class Meta:
        app_label = 'notes'
        abstract = dd.is_abstract_model(__name__, 'Note')
        verbose_name = _("Note")
        verbose_name_plural = _("Notes")

    date = models.DateField(verbose_name=_('Date'), default=dd.today)
    time = models.TimeField(blank=True,
                            null=True,
                            verbose_name=_("Time"),
                            default=timezone.now)
    type = dd.ForeignKey('notes.NoteType',
                         blank=True,
                         null=True,
                         verbose_name=_('Note Type (Content)'))
    event_type = dd.ForeignKey('notes.EventType',
                               blank=True,
                               null=True,
                               verbose_name=_('Event Type (Form)'))
    subject = models.CharField(_("Subject"), max_length=200, blank=True)
    body = dd.RichTextField(_("Body"), blank=True, format='html')

    language = dd.LanguageField()

    def __str__(self):
        return u'%s #%s' % (self._meta.verbose_name, self.pk)

    def summary_row(self, ar, **kw):
        #~ s = super(Note,self).summary_row(ui,rr)
        s = super(Note, self).summary_row(ar)
        #~ s = contacts.ContactDocument.summary_row(self,ui,rr)
        if self.subject:
            s += [' ', self.subject]
        return s

    def get_mailable_type(self):
        return self.type

    def get_print_language(self):
        return self.language
示例#10
0
文件: models.py 项目: TonisPiip/xl
class RecurrentEvent(mixins.BabelNamed, RecurrenceSet, EventGenerator):
    """A rule designed to generate a series of recurrent events.
    
    .. attribute:: name

        See :attr:`lino.utils.mldbc.mixins.BabelNamed.name`.
    
    .. attribute:: every_unit

        Inherited from :attr:`RecurrentSet.every_unit
        <lino_xl.lib.cal.models.RecurrentSet.every_unit>`.

    .. attribute:: event_type



    .. attribute:: description

    """
    class Meta:
        app_label = 'cal'
        verbose_name = _("Recurrent event rule")
        verbose_name_plural = _("Recurrent event rules")

    event_type = models.ForeignKey('cal.EventType', blank=True, null=True)
    description = dd.RichTextField(
        _("Description"), blank=True, format='html')

    def before_auto_event_save(self, obj):
        if self.end_date:  # and self.end_date != self.start_date:
            duration = self.end_date - self.start_date
            obj.end_date = obj.start_date + duration
        super(RecurrentEvent, self).before_auto_event_save(obj)

    # def on_create(self,ar):
        # super(RecurrentEvent,self).on_create(ar)
        # self.event_type = settings.SITE.site_config.holiday_event_type

    # def __unicode__(self):
        # return self.summary

    def update_cal_rset(self):
        return self

    def update_cal_from(self, ar):
        return self.start_date

    def update_cal_event_type(self):
        return self.event_type

    def update_cal_summary(self, i):
        return six.text_type(self)

    def care_about_conflicts(self, we):
        """Recurrent events don't care about conflicts. A holiday won't move
        just because some other event has been created before on that date.

        """
        return False
示例#11
0
class Room(mixins.BabelNamed, ContactRelated, Colored):
    class Meta:
        app_label = 'cal'
        abstract = dd.is_abstract_model(__name__, 'Room')
        verbose_name = _("Room")
        verbose_name_plural = _("Rooms")

    description = dd.RichTextField(_("Description"), blank=True)
示例#12
0
文件: models.py 项目: TonisPiip/book
class Entry(UserAuthored):
    class Meta:
        verbose_name = _("Entry")
        verbose_name_plural = _("Entries")

    subject = models.CharField(_("Subject"), blank=True, max_length=200)
    body = dd.RichTextField(_("Body"), blank=True)
    company = models.ForeignKey('contacts.Company')
示例#13
0
文件: models.py 项目: DarioGT/lino
class EventType(mixins.BabelNamed, mixins.Sequenced, MailableType):
    """The possible value of the :attr:`Event.type` field.
    Example content:

    .. lino2rst::

       rt.show(cal.EventTypes, limit=5)

    .. attribute:: is_appointment

        Whether events of this type should be considered
        "appointments" (i.e. whose time and place have been agreed
        upon with other users or external parties).

        The table (:class:`EventsByDay` and
        :class:`MyEvents`) show only events whose type has the
        `is_appointment` field checked.

    """
    templates_group = 'cal/Event'

    class Meta:
        app_label = 'cal'
        abstract = dd.is_abstract_model(__name__, 'EventType')
        verbose_name = _("Calendar Event Type")
        verbose_name_plural = _("Calendar Event Types")
        ordering = ['seqno']

    description = dd.RichTextField(_("Description"), blank=True, format='html')
    is_appointment = models.BooleanField(_("Event is an appointment"),
                                         default=True)
    all_rooms = models.BooleanField(_("Locks all rooms"), default=False)
    locks_user = models.BooleanField(
        _("Locks the user"),
        help_text=_("Whether events of this type make the user unavailable "
                    "for other locking events at the same time."),
        default=False)

    start_date = models.DateField(verbose_name=_("Start date"),
                                  blank=True,
                                  null=True)
    event_label = dd.BabelCharField(_("Event label"),
                                    max_length=200,
                                    blank=True)
    # , default=_("Calendar entry"))
    # default values for a Babelfield don't work as expected

    max_conflicting = models.PositiveIntegerField(
        _("Simultaneous events"),
        help_text=_("How many conflicting events should be tolerated."),
        default=1)

    def __unicode__(self):
        # when selecting an Event.event_type it is more natural to
        # have the event_label. It seems that the current `name` field
        # is actually never used.
        return settings.SITE.babelattr(self, 'event_label') \
            or settings.SITE.babelattr(self, 'name')
示例#14
0
class Filter(dd.Model):
    name = models.CharField(_("Name"), max_length=200)
    content_type = dd.ForeignKey(contenttypes.ContentType,
                                 verbose_name=_("Model"))
    field_sep = models.CharField(_("Field separator"), max_length=10)
    help_text = dd.RichTextField(_("HelpText"),
                                 blank=True,
                                 null=True,
                                 format='plain')
示例#15
0
文件: models.py 项目: einarfelix/xl
class Competence(UserAuthored, Sequenced):
    """A **skill offer** is when a given *user* is declared to have a
    given *skill*.

    .. attribute:: user
    .. attribute:: end_user
    .. attribute:: faculty
    .. attribute:: affinity

    """

    allow_cascaded_delete = "end_user user"

    class Meta:
        verbose_name = _("Skill offer")
        verbose_name_plural = _("Skill offers")
        unique_together = ['end_user', 'faculty']

    faculty = dd.ForeignKey('skills.Skill')
    end_user = dd.ForeignKey(dd.plugins.skills.end_user_model,
                             verbose_name=_("End user"),
                             blank=True,
                             null=True)
    # supplier = dd.ForeignKey(
    #     dd.plugins.skills.supplier_model,
    #     verbose_name=_("Supplier"),
    #     blank=True, null=True)
    affinity = models.IntegerField(
        _("Affinity"),
        blank=True,
        default=MAX_WEIGHT,
        help_text=_("How much this user likes to get a new ticket "
                    "in this faculty."
                    "A number between -{0} and +{0}.").format(MAX_WEIGHT))
    description = dd.RichTextField(_("Description"), blank=True)

    # topic = dd.ForeignKey(
    #     'topics.Topic', blank=True, null=True,
    #     verbose_name=_("Option"),
    #     help_text=_("Some skills can require additional "
    #                 "options for a competence."))

    # @dd.chooser()
    # def topic_choices(cls, faculty):
    #     Topic = rt.models.topics.Topic
    #     if not faculty or not faculty.topic_group:
    #         return Topic.objects.none()
    #     return Topic.objects.filter(topic_group=faculty.topic_group)

    def full_clean(self, *args, **kw):
        if self.affinity is None:
            self.affinity = self.faculty.affinity
        # if self.faculty.product_cat:
        #     if not self.product:
        #         raise ValidationError(
        #             "A {0} competence needs a {1} as option")
        super(Competence, self).full_clean(*args, **kw)
示例#16
0
文件: models.py 项目: NewRGB/lino
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
示例#17
0
class Entry(UserAuthored):
    
    class Meta:
        verbose_name = _("Entry")
        verbose_name_plural = _("Entries")
        
    date = models.DateField(_("Date"))
    entry_type = dd.ForeignKey(EntryType)
    subject = models.CharField(_("Subject"), blank=True, max_length=200)
    body = dd.RichTextField(_("Body"), blank=True)
    company = dd.ForeignKey(Company)
示例#18
0
文件: models.py 项目: DarioGT/lino
class Entry(mixins.CreatedModified, UserAuthored):

    workflow_state_field = 'state'

    class Meta:
        verbose_name = _("Entry")
        verbose_name_plural = _("Entries")

    subject = models.CharField(_("Subject"), blank=True, max_length=200)
    body = dd.RichTextField(_("Body"), blank=True)
    company = models.ForeignKey('contacts.Company', blank=True, null=True)
    state = EntryStates.field(blank=True, default=EntryStates.todo)
示例#19
0
class ChatGroup(UserAuthored, Created, Referrable):
    class Meta(object):
        app_label = 'chat'
        verbose_name = _("Chat group")
        verbose_name_plural = _("Chat groups")
        ordering = ['created', 'id']

    title = dd.CharField(max_length=20)
    description = dd.RichTextField(max_length=200, blank=True, null=True)
    ticket = dd.ForeignKey("tickets.Ticket", blank=True, null=True)

    @dd.action(_("getChatGroups"))
    def getChatGroups(self, ar):
        """
        Returns info on all GroupChats for this user.
        """
        qs = ChatGroupMember.objects.filter(
            user=ar.get_user()).select_related("group")

        rows = [{
            "id": cp.group.pk,
            "title": cp.group.title,
            "unseen": cp.group.get_unseen_count(ar)
        } for cp in qs]

        return ar.success(rows=rows)

    def get_unseen_count(self, ar):
        """
        Returns count of messages that haven't been seen yet."""
        return ChatProps.objects.filter(chat__group=self,
                                        user=ar.get_user(),
                                        seen__isnull=True).count()

    @dd.action(_("Load GroupChat"))
    def loadGroupChat(self, ar):
        """Returns chat messages for a given chat"""
        rows = []
        if 'mk' in ar.rqdata:
            # master = rt.models.resolve("contenttypes.ContentType").get(pk=ar.rqdata['mt']).get(pk=ar.rqdata["mk"])
            ar.selected_rows = [
                ChatGroup.objects.get(ticket__pk=ar.rqdata['mk'])
            ]
        for group in ar.selected_rows:
            last_ten = ChatProps.objects.filter(
                user=ar.get_user(),
                chat__group=group).order_by('-created').select_related("chat")
            rows.append({
                'title': group.title,
                'id': group.id,
                'messages': [cp.serialize(ar) for cp in last_ten]
            })
        return ar.success(rows=rows)
示例#20
0
文件: models.py 项目: DarioGT/lino
class HelpText(dd.Model):
    """A custom help text to be displayed for a given field."""
    class Meta:
        verbose_name = _("Help Text")
        verbose_name_plural = _("Help Texts")

    content_type = models.ForeignKey('contenttypes.ContentType',
                                     verbose_name=_("Model"))
    field = models.CharField(_("Field"), max_length=200)

    help_text = dd.RichTextField(_("HelpText"),
                                 blank=True,
                                 null=True,
                                 format='plain')

    def __unicode__(self):
        return self.content_type.app_label + '.' \
            + self.content_type.model + '.' + self.field

    @dd.chooser(simple_values=True)
    def field_choices(cls, content_type):
        l = []
        if content_type is not None:
            model = content_type.model_class()
            meta = model._meta
            for f in meta.fields:
                if not getattr(f, '_lino_babel_field', False):
                    l.append(f.name)
            for f in meta.many_to_many:
                l.append(f.name)
            for f in meta.virtual_fields:
                l.append(f.name)
            for a in model.get_default_table().get_actions():
                l.append(a.action.action_name)
            l.sort()
        return l

    #~ def get_field_display(cls,fld):
    #~ return fld

    @dd.virtualfield(models.CharField(_("Verbose name"), max_length=200))
    def verbose_name(self, request):
        m = self.content_type.model_class()
        de = m.get_default_table().get_data_elem(self.field)
        if isinstance(de, models.Field):
            return "%s (%s)" % (unicode(
                de.verbose_name), unicode(_("database field")))
        if isinstance(de, dd.VirtualField):
            return unicode(de.return_type.verbose_name)
        if isinstance(de, dd.Action):
            return unicode(de.label)
        return str(de)
示例#21
0
文件: models.py 项目: TonisPiip/xl
class Calendar(mixins.BabelNamed):

    COLOR_CHOICES = [i + 1 for i in range(32)]

    class Meta:
        app_label = 'cal'
        abstract = dd.is_abstract_model(__name__, 'Calendar')
        verbose_name = _("Calendar")
        verbose_name_plural = _("Calendars")

    description = dd.RichTextField(_("Description"), blank=True, format='html')

    color = models.IntegerField(
        _("color"), default=default_color,
        validators=[MinValueValidator(1), MaxValueValidator(32)]
    )
示例#22
0
文件: models.py 项目: DarioGT/lino
class Entry(mixins.TypedPrintable, mixins.CreatedModified, UserAuthored,
            Controllable):
    """
    Deserves more documentation.
    """
    class Meta:
        verbose_name = _("Blog Entry")
        verbose_name_plural = _("Blog Entries")

    language = dd.LanguageField()
    type = models.ForeignKey(EntryType, blank=True, null=True)
    # ,null=True)
    title = models.CharField(_("Heading"), max_length=200, blank=True)
    body = dd.RichTextField(_("Body"), blank=True, format='html')

    def __unicode__(self):
        return u'%s #%s' % (self._meta.verbose_name, self.pk)
示例#23
0
class ProductDocItem(ledger.VoucherItem, vat.QtyVatItemBase):
    product = dd.ForeignKey('products.Product', blank=True, null=True)
    #~ title = models.CharField(max_length=200,blank=True)
    description = dd.RichTextField(_("Description"), blank=True, null=True)
    discount = models.IntegerField(_("Discount"), default=0)

    def get_base_account(self, tt):
        ref = tt.get_product_base_account(self.product)
        return rt.models.ledger.Account.get_by_ref(ref)

    def product_changed(self, ar):
        if self.product:
            self.title = self.product.name
            self.description = self.product.description
            if self.qty is None:
                self.qty = Decimal("1")
            if self.product.price is not None:
                self.unit_price = myround(self.product.price * \
                    (HUNDRED - self.discount) / HUNDRED)
                self.unit_price_changed(ar)
示例#24
0
class Interest(Controllable):
    class Meta:
        app_label = 'topics'
        verbose_name = _("Interest")
        verbose_name_plural = _('Interests')

    allow_cascaded_delete = ["partner"]

    topic = dd.ForeignKey('topics.Topic', related_name='interests_by_topic')

    remark = dd.RichTextField(_("Remark"), blank=True, format="plain")

    # def __str__(self):
    #     return str(self.topic)

    # used in lino_tera
    partner = dd.ForeignKey(dd.plugins.topics.partner_model,
                            related_name='interests_by_partner',
                            blank=True,
                            null=True)
示例#25
0
文件: models.py 项目: einarfelix/xl
class EventType(mixins.BabelNamed, Referrable, mixins.Sequenced, MailableType):
    templates_group = 'cal/Event'
    ref_max_length = 4

    class Meta:
        app_label = 'cal'
        abstract = dd.is_abstract_model(__name__, 'EventType')
        verbose_name = _("Calendar entry type")
        verbose_name_plural = _("Calendar entry types")
        ordering = ['seqno']

    description = dd.RichTextField(_("Description"), blank=True, format='html')
    is_appointment = models.BooleanField(_("Appointment"), default=True)
    all_rooms = models.BooleanField(_("Locks all rooms"), default=False)
    locks_user = models.BooleanField(_("Locks the user"), default=False)
    force_guest_states = models.BooleanField(_("Automatic presences"),
                                             default=False)
    fill_presences = models.BooleanField(_("Fill guests"), default=False)

    start_date = models.DateField(verbose_name=_("Start date"),
                                  blank=True,
                                  null=True)
    event_label = dd.BabelCharField(_("Entry label"),
                                    max_length=200,
                                    blank=True)
    # , default=_("Calendar entry"))
    # default values for a Babelfield don't work as expected

    max_conflicting = models.PositiveIntegerField(_("Simultaneous entries"),
                                                  default=1)
    max_days = models.PositiveIntegerField(_("Maximum days"), default=1)
    transparent = models.BooleanField(_("Transparent"), default=False)

    planner_column = PlannerColumns.field(blank=True)

    # default_duration = models.TimeField(
    #     _("Default duration"), blank=True, null=True)

    default_duration = dd.DurationField(_("Default duration"),
                                        blank=True,
                                        null=True)
示例#26
0
文件: models.py 项目: einarfelix/xl
class Skill(BabelNamed, Hierarchical, Sequenced):
    """A **skill** is a knowledge or ability which can be
    required in order to work e.g. on some ticket, and which
    individual users can have (offer) or not.

    """
    class Meta:
        verbose_name = _("Skill")
        verbose_name_plural = _("Skills")
        ordering = ['name']

    affinity = models.IntegerField(
        _("Affinity"),
        blank=True,
        default=MAX_WEIGHT,
        help_text=_("How much workers enjoy to get a new ticket "
                    "requiring this skill."
                    "A number between -{0} and +{0}.").format(MAX_WEIGHT))

    skill_type = dd.ForeignKey('skills.SkillType', null=True, blank=True)

    remarks = dd.RichTextField(_("Remarks"), blank=True)
示例#27
0
class MarkVoteRated(VoteAction):
    """Rate this vote and mark it as rated.

    .. attribute:: rating

        How you rate this job.

    .. attribute:: comment

        Your comment related to your rating.

    """
    label = _("Rate")
    managed_by_votable_author = True
    required_states = 'assigned done invited'
    required_votable_states = 'new talk opened started ready'
    parameters = dict(rating=Ratings.field(),
                      comment=dd.RichTextField(_("Comment"), blank=True))
    # params_layout = dd.ParamsLayout("""
    params_layout = dd.Panel("""
    rating
    comment
    """,
                             window_size=(50, 12))

    # def param_defaults(self, obj, ar, **kw):
    #     kw.update(rating=obj.rating)
    #     return kw

    def before_execute(self, ar, obj):
        pv = ar.action_param_values
        # print(20170116, pv)
        obj.rating = pv.rating
        if pv.comment:
            create_row(rt.models.comments.Comment,
                       owner=obj.votable,
                       short_text=pv.comment,
                       user=ar.get_user())
示例#28
0
文件: models.py 项目: TonisPiip/lino
class Message(UserAuthored, Controllable, Created):
    """A **Notification message** is a instant message sent by the
    application to a given user.

    Applications can either use it indirectly by sublassing
    :class:`ChangeObservable
    <lino.modlib.notify.mixins.ChangeObservable>` or by directly
    calling the class method :meth:`create_message` to create a new
    message.


    .. attribute:: subject
    .. attribute:: body
    .. attribute:: user

        The recipient.

    .. attribute:: owner
 
       The database object which controls this message. 

       This may be `None`, which means that the message has no
       controller. When a notification is controlled, then the
       recipient will receive only the first message for that object.
       Any following message is ignored until the recipient has
       "confirmed" the first message. Typical use case are the
       messages emitted by :class:`ChangeObservable`: you don't want
       to get 10 mails just because a colleague makes 10 small
       modifications when authoring the text field of a
       ChangeObservable object.

    .. attribute:: created
    .. attribute:: sent
    .. attribute:: seen

    """
    class Meta(object):
        app_label = 'notify'
        verbose_name = _("Notification message")
        verbose_name_plural = _("Notification messages")

    message_type = MessageTypes.field()
    seen = models.DateTimeField(_("seen"), null=True, editable=False)
    sent = models.DateTimeField(_("sent"), null=True, editable=False)
    body = dd.RichTextField(_("Body"), editable=False, format='html')
    mail_mode = MailModes.field(default=MailModes.often.as_callable)
    subject = models.CharField(_("Subject"), max_length=250, editable=False)

    def __str__(self):
        return "{} #{}".format(self.message_type, self.id)

        # return _("About {0}").format(self.owner)

    # return self.message
    # return _("Notify {0} about change on {1}").format(
    #     self.user, self.owner)

    @classmethod
    def emit_message(cls, ar, owner, message_type, msg_func, recipients):
        """Create one database object for every recipient.

        `recipients` is a list of `(user, mail_mode)` tuples.

        `msg_func` is a callable expected to return a tuple (subject,
        body). It is called for each recipient (in the recipient's
        language).

        The changing user does not get notified about their own
        changes, except when working as another user.

        """
        # dd.logger.info("20160717 %s emit_messages()", self)
        others = set()
        me = ar.get_user()
        for user, mm in recipients:
            if user:
                if user != me or me.notify_myself:
                    others.add((user, mm))

        if len(others):
            # subject = "{} by {}".format(message_type, me)
            # dd.logger.info(
            #     "Notify %s users about %s", len(others), subject)
            for user, mm in others:
                with dd.translation.override(user.language):
                    subject_body = msg_func(user, mm)
                    if subject_body is not None:
                        subject, body = subject_body
                        cls.create_message(user,
                                           owner,
                                           body=body,
                                           subject=subject,
                                           mail_mode=mm,
                                           message_type=message_type)

    @classmethod
    def create_message(cls, user, owner=None, **kwargs):
        """Create a message unless that user has already been notified
        about that object.

        """
        if owner is not None:
            fltkw = gfk2lookup(cls.owner, owner)
            qs = cls.objects.filter(user=user, seen__isnull=True, **fltkw)
            if qs.exists():
                return
        obj = cls(user=user, owner=owner, **kwargs)
        obj.full_clean()
        obj.save()
        if settings.SITE.use_websockets:
            obj.send_browser_message(user)

    # @dd.displayfield(_("Subject"))
    # def subject_more(self, ar):
    #     if ar is None:
    #         return ''
    #     elems = [self.subject]
    #     if self.body:
    #         elems.append(' ')
    #         # elems.append(ar.obj2html(self, _("(more)")))
    #         elems.append(E.raw(self.body))
    #     # print 20160908, elems
    #     return E.p(*elems)

    # @dd.displayfield(_("Overview"))
    # def overview(self, ar):
    #     if ar is None:
    #         return ''
    #     return self.get_overview(ar)

    # def get_overview(self, ar):
    #     """Return the content to be displayed in the :attr:`overview` field.
    #     On interactive rendererers (extjs, bootstrap3) the `obj` and
    #     `user` are clickable.

    #     This is also used from the :xfile:`notify/body.eml` template
    #     where they should just be surrounded by **double asterisks**
    #     so that Thunderbird displays them bold.

    #     """
    #     elems = body_subject_to_elems(ar, self.subject, self.body)
    #     return E.div(*elems)
    #     # context = dict(
    #     #     obj=ar.obj2str(self.owner),
    #     #     user=ar.obj2str(self.user))
    #     # return _(self.message).format(**context)
    #     # return E.p(
    #     #     ar.obj2html(self.owner), " ",
    #     #     _("was modified by {0}").format(self.user))

    def unused_send_individual_email(self):
        """"""
        if not self.user.email:
            # debug level because we don't want to see this message
            # every 10 seconds:
            dd.logger.debug("User %s has no email address", self.user)
            return
        # dd.logger.info("20151116 %s %s", ar.bound_action, ar.actor)
        # ar = ar.spawn_request(renderer=dd.plugins.bootstrap3.renderer)
        # sar = BaseRequest(
        #     # user=self.user, renderer=dd.plugins.bootstrap3.renderer)
        #     user=self.user, renderer=settings.SITE.kernel.text_renderer)
        # tpl = dd.plugins.notify.email_subject_template
        # subject = tpl.format(obj=self)
        if self.owner is None:
            subject = str(self)
        else:
            subject = pgettext("notification",
                               "{} in {}").format(self.message_type,
                                                  self.owner)
        subject = settings.EMAIL_SUBJECT_PREFIX + subject
        # template = rt.get_template('notify/body.eml')
        # context = dict(obj=self, E=E, rt=rt, ar=sar)
        # body = template.render(**context)

        template = rt.get_template('notify/individual.eml')
        context = dict(obj=self, E=E, rt=rt)
        body = template.render(**context)

        sender = settings.SERVER_EMAIL
        rt.send_email(subject, sender, body, [self.user.email])
        self.sent = timezone.now()
        self.save()

    # for testing, set show_in_workflow to True:
    # @dd.action(label=_("Send e-mail"),
    #            show_in_bbar=False, show_in_workflow=False,
    #            button_text="✉")  # u"\u2709"
    # def do_send_email(self, ar):
    #     self.send_individual_email()

    # @dd.action(label=_("Seen"),
    #            show_in_bbar=False, show_in_workflow=True,
    #            button_text="✓")  # u"\u2713"
    # def mark_seen(self, ar):
    #     self.seen = timezone.now()
    #     self.save()
    #     ar.success(refresh_all=True)

    mark_all_seen = MarkAllSeen()
    mark_seen = MarkSeen()
    clear_seen = ClearSeen()

    @classmethod
    def send_summary_emails(cls, mm):
        """Send summary emails for all pending notifications with the given
        mail_mode `mm`.

        """
        qs = cls.objects.filter(sent__isnull=True)
        qs = qs.exclude(user__email='')
        qs = qs.filter(mail_mode=mm).order_by('user')
        if qs.count() == 0:
            return
        from lino.core.renderer import MailRenderer
        ar = rt.login(renderer=MailRenderer())
        context = ar.get_printable_context()
        sender = settings.SERVER_EMAIL
        template = rt.get_template('notify/summary.eml')
        users = dict()
        for obj in qs:
            lst = users.setdefault(obj.user, [])
            lst.append(obj)
        dd.logger.debug("Send out %s summaries for %d users.", mm, len(users))
        for user, messages in users.items():
            with translation.override(user.language):
                if len(messages) == 1:
                    subject = messages[0].subject
                else:
                    subject = _("{} notifications").format(len(messages))
                subject = settings.EMAIL_SUBJECT_PREFIX + subject
                context.update(user=user, messages=messages)
                body = template.render(**context)
                # dd.logger.debug("20170112 %s", body)
                rt.send_email(subject, sender, body, [user.email])
                for msg in messages:
                    msg.sent = timezone.now()
                    msg.save()

    def send_browser_message_for_all_users(self, user):
        """
        Send_message to all connected users
        """

        message = {
            "id": self.id,
            "subject": self.subject,
            "body": html2text(self.body),
            "created": self.created.strftime("%a %d %b %Y %H:%M"),
        }

        # Encode and send that message to the whole channels Group for our
        # liveblog. Note how you can send to a channel or Group from any part
        # of Django, not just inside a consumer.
        from channels import Group
        Group(PUBLIC_GROUP).send({
            # WebSocket text frame, with JSON content
            "text": json.dumps(message),
        })

        return

    def send_browser_message(self, user):
        """
        Send_message to the user's browser
        """

        message = {
            "id": self.id,
            "subject": str(self.subject),
            "body": html2text(self.body),
            "created": self.created.strftime("%a %d %b %Y %H:%M"),
        }

        # Encode and send that message to the whole channels Group for our
        # Websocket. Note how you can send to a channel or Group from any part
        # of Django, not just inside a consumer.
        from channels import Group
        Group(user.username).send({
            # WebSocket text frame, with JSON content
            "text": json.dumps(message),
        })

        return
示例#29
0
文件: models.py 项目: forexblog/xl
class Deployment(Sequenced, Workable):
    class Meta:
        app_label = 'deploy'
        verbose_name = _("Wish")
        verbose_name_plural = _('Wishes')

    # SpawnTicket = SpawnTicketFromWish(_("New Ticket"), LinkTypes.triggers)

    allow_cascaded_copy = 'milestone'
    ticket = dd.ForeignKey('tickets.Ticket',
                           related_name="deployments_by_ticket")
    milestone = dd.ForeignKey(dd.plugins.tickets.milestone_model,
                              related_name="wishes_by_milestone")
    remark = dd.RichTextField(_("Remark"), blank=True, format="plain")
    # remark = models.CharField(_("Remark"), blank=True, max_length=250)
    wish_type = WishTypes.field(blank=True, null=True)
    old_ticket_state = TicketStates.field(blank=True,
                                          null=True,
                                          verbose_name=_("Ticket State"))
    new_ticket_state = TicketStates.field(blank=True,
                                          null=True,
                                          verbose_name=_("New Ticket State"))
    deferred_to = dd.ForeignKey(dd.plugins.tickets.milestone_model,
                                verbose_name=_("Deferred to"),
                                blank=True,
                                null=True,
                                related_name="wishes_by_deferred")

    def get_ticket(self):
        return self.ticket

    def get_siblings(self):
        "Overrides :meth:`lino.mixins.Sequenced.get_siblings`"
        qs = self.__class__.objects.filter(milestone=self.milestone)
        # print(20170321, qs)
        return qs

    @dd.chooser()
    def unused_milestone_choices(cls, ticket):
        # if not ticket:
        #     return []
        # if ticket.site:
        #     return ticket.site.milestones_by_site.all()
        qs = rt.models.deploy.Milestone.objects.filter(closed=False)
        qs = qs.order_by('label')
        return qs

    def __str__(self):
        return "{}@{}".format(self.seqno, self.milestone)

    def full_clean(self):
        super(Deployment, self).full_clean()
        if self.deferred_to:
            if self.milestone == self.deferred_to:
                raise Warning(_("Cannot defer to myself"))
            qs = rt.models.deploy.Deployment.objects.filter(
                milestone=self.deferred_to, ticket=self.ticket)
            if qs.count() == 0:
                create_row(Deployment,
                           milestone=self.deferred_to,
                           ticket=self.ticket,
                           wish_type=self.wish_type,
                           remark=self.remark)

    def milestone_changed(self, ar):
        self.ticket_changed(ar)

    def ticket_changed(self, ar):
        if self.ticket is not None and self.milestone is not None:
            self.milestone.add_child_stars(self.milestone, self.ticket)

    def after_ui_create(self, ar):
        # print "Create"
        self.ticket_changed(ar)
        super(Deployment, self).after_ui_create(ar)

    # def after_ui_save(self, ar, cw):
    #     """
    #     Automatically invite every participant to vote on every wish when adding deployment.
    #     """
    #     super(Deployment, self).after_ui_save(ar, cw)
    #     self.milestone.after_ui_save(ar, cw)

    @dd.displayfield(_("Actions"))
    def workflow_buttons(self, ar, **kwargs):
        if ar is None:
            return ''
        l = super(Deployment, self).get_workflow_buttons(ar)

        sar = rt.models.comments.CommentsByRFC.insert_action.request_from(ar)

        owner = ContentType.objects.get(app_label='tickets', model="ticket")
        # sar.bound_action.icon_name = None
        # sar.bound_action.label = _(" New Comment")

        sar.known_values.update(
            owner_id=self.ticket.id,
            owner_type=owner,
            # owner=self.ticket,
            user=ar.get_user())
        if sar.get_permission():
            l.append(E.span(u", "))
            l.append(sar.ar2button(icon_name=None, label=_("New Comment")))
        # print self.E.tostring(l)
        return l
示例#30
0
class Client(contacts.Person, BeIdCardHolder, UserAuthored, ClientBase,
             BiographyOwner, Referrable, Dupable, Lockable, Commentable,
             EventGenerator, Enrollable, TrendObservable):
    class Meta:
        app_label = 'avanti'
        verbose_name = _("Client")
        verbose_name_plural = _("Clients")
        abstract = dd.is_abstract_model(__name__, 'Client')
        #~ ordering = ['last_name','first_name']

    quick_search_fields = "name phone gsm ref"

    is_obsolete = False  # coachings checker

    beid_readonly_fields = set()
    manager_roles_required = dd.login_required(ClientsUser)
    validate_national_id = True
    _cef_levels = None
    _mother_tongues = None

    # in_belgium_since = models.DateField(
    #     _("Lives in Belgium since"), blank=True, null=True)

    in_belgium_since = dd.IncompleteDateField(_("Lives in Belgium since"),
                                              blank=True,
                                              null=True)

    in_region_since = dd.IncompleteDateField(_("Lives in region since"),
                                             blank=True,
                                             null=True)

    starting_reason = StartingReasons.field(blank=True)
    old_ending_reason = OldEndingReasons.field(blank=True)
    ending_reason = dd.ForeignKey('avanti.EndingReason', blank=True, null=True)
    professional_state = ProfessionalStates.field(blank=True)
    category = dd.ForeignKey('avanti.Category', blank=True, null=True)

    translator_type = TranslatorTypes.field(blank=True)
    translator_notes = dd.RichTextField(_("Translator"),
                                        blank=True,
                                        format='plain')
    # translator = dd.ForeignKey(
    #     "avanti.Translator",
    #     blank=True, null=True)

    unemployed_since = models.DateField(
        _("Unemployed since"),
        blank=True,
        null=True,
        help_text=_("Since when the client has not been employed "
                    "in any regular job."))
    seeking_since = models.DateField(
        _("Seeking work since"),
        blank=True,
        null=True,
        help_text=_("Since when the client is seeking for a job."))
    needs_work_permit = models.BooleanField(_("Needs work permit"),
                                            default=False)
    work_permit_suspended_until = models.DateField(
        blank=True, null=True, verbose_name=_("suspended until"))
    has_contact_pcsw = models.BooleanField(_("Has contact to PCSW"),
                                           default=False)
    has_contact_work_office = models.BooleanField(
        _("Has contact to work office"), default=False)

    declared_name = models.BooleanField(_("Declared name"), default=False)

    # is_seeking = models.BooleanField(_("is seeking work"), default=False)
    # removed in chatelet, maybe soon also in Eupen (replaced by seeking_since)

    unavailable_until = models.DateField(blank=True,
                                         null=True,
                                         verbose_name=_("Unavailable until"))
    unavailable_why = models.CharField(_("Reason"), max_length=100, blank=True)

    family_notes = models.TextField(_("Family situation"),
                                    blank=True,
                                    null=True)

    residence_notes = models.TextField(_("Residential situation"),
                                       blank=True,
                                       null=True)

    health_notes = models.TextField(_("Health situation"),
                                    blank=True,
                                    null=True)

    financial_notes = models.TextField(_("Financial situation"),
                                       blank=True,
                                       null=True)

    integration_notes = models.TextField(_("Integration notes"),
                                         blank=True,
                                         null=True)

    availability = models.TextField(_("Availability"), blank=True, null=True)

    needed_course = dd.ForeignKey('courses.Line',
                                  verbose_name=_("Needed course"),
                                  blank=True,
                                  null=True)

    # obstacles = models.TextField(
    #     _("Other obstacles"), blank=True, null=True)
    # skills = models.TextField(
    #     _("Other skills"), blank=True, null=True)

    # client_state = ClientStates.field(
    #     default=ClientStates.newcomer.as_callable)

    event_policy = dd.ForeignKey('cal.EventPolicy', blank=True, null=True)

    language_notes = dd.RichTextField(_("Language notes"),
                                      blank=True,
                                      format='plain')

    remarks = dd.RichTextField(_("Remarks"), blank=True, format='plain')

    reason_of_stay = models.CharField(_("Reason of stay"),
                                      max_length=200,
                                      blank=True)

    nationality2 = dd.ForeignKey('countries.Country',
                                 blank=True,
                                 null=True,
                                 related_name='by_nationality2',
                                 verbose_name=format_lazy(
                                     u"{}{}", _("Nationality"), " (2)"))

    def __str__(self):
        info = str(self.pk)
        u = self.user
        if u is not None:
            # info = (str(u.initials or u) + " " + info).strip()
            info += "/" + str(u.initials or u.username)
        return "%s %s (%s)" % (self.last_name.upper(), self.first_name, info)

    def get_choices_text(self, ar, actor, field):
        if ar:
            u = ar.subst_user or ar.user
            if u.user_type.has_required_roles([ClientsNameUser]):
                return str(self)
        # 20180209 : not even the first name
        # return _("{} ({}) from {}").format(
        #     self.first_name, self.pk, self.city)
        return _("({}) from {}").format(self.pk, self.city)
        # return "{} {}".format(self._meta.verbose_name, self.pk)

    def get_overview_elems(self, ar):
        elems = super(Client, self).get_overview_elems(ar)
        # elems.append(E.br())
        elems.append(ar.get_data_value(self, 'eid_info'))
        notes = []
        for obj in rt.models.cal.Task.objects.filter(
                project=self, state=TaskStates.important):
            notes.append(E.b(ar.obj2html(obj, obj.summary)))
        if len(notes):
            notes = join_elems(notes, " / ")
            elems.append(E.p(*notes, **{'class': "lino-info-yellow"}))
        return elems

    def update_owned_instance(self, owned):
        owned.project = self
        super(Client, self).update_owned_instance(owned)

    def full_clean(self, *args, **kw):
        prefix = "IP"
        num_width = 4
        if self.ref and self.ref.upper().startswith(prefix):
            num_root = self.ref[len(prefix):].strip()
            if len(num_root) == num_width:
                ref_num = num_root
            else:
                qs = self.__class__.objects.filter(
                    ref__startswith="{} {}".format(prefix, num_root)).order_by(
                        "ref")
                qs = qs.exclude(id=self.id)
                obj = qs.last()
                if obj is None:
                    last_ref = num_root.ljust(num_width, "0")
                else:
                    last_ref = obj.ref[len(prefix):].strip()
                ref_num = str(int(last_ref) + 1)
            self.ref = "{} {}".format(prefix, ref_num)

        # if self.national_id:
        #     ssin.ssin_validator(self.national_id)
        super(Client, self).full_clean(*args, **kw)

    def properties_list(self, *prop_ids):
        """Yields a list of the :class:`PersonProperty
        <lino_welfare.modlib.cv.models.PersonProperty>` properties of
        this person in the specified order.  If this person has no
        entry for a requested :class:`Property`, it is simply skipped.
        Used in :xfile:`cv.odt`.  `

        """
        return rt.models.cv.properties_list(self, *prop_ids)

    def get_events_user(self):
        return self.get_primary_coach()

    def update_cal_rset(self):
        return self.event_policy

    def update_cal_event_type(self):
        if self.event_policy is not None:
            return self.event_policy.event_type

    def update_cal_from(self, ar):
        return dd.today()
        # pc = self.get_primary_coaching()
        # if pc:
        #     return pc.start_date

    def update_cal_until(self):
        return dd.today(365)
        # pc = self.get_primary_coaching()
        # if pc:
        #     return pc.end_date

    def get_dupable_words(self, s):
        s = strip_name_prefix(s)
        return super(Client, self).get_dupable_words(s)

    def find_similar_instances(self, limit=None, **kwargs):
        """Overrides
        :meth:`lino.modlib.dupable.mixins.Dupable.find_similar_instances`,
        adding some additional rules.

        """
        # kwargs.update(is_obsolete=False, national_id__isnull=True)
        qs = super(Client, self).find_similar_instances(None, **kwargs)
        if self.national_id:
            qs = qs.filter(national_id__isnull=True)
        # else:
        #     qs = qs.filter(national_id__isnull=False)
        if self.birth_date:
            qs = qs.filter(Q(birth_date='') | Q(birth_date=self.birth_date))

        last_name_words = set(self.get_dupable_words(self.last_name))

        found = 0
        for other in qs:
            found += 1
            if limit is not None and found > limit:
                return
            ok = False
            for w in other.get_dupable_words(other.last_name):
                if w in last_name_words:
                    ok = True
                    break
            if ok:
                yield other