def inject_summary_fields(sender, **kw): SiteSummary = rt.models.working.SiteSummary UserSummary = rt.models.working.UserSummary WorkSite = rt.models.tickets.Site Ticket = dd.plugins.working.ticket_model for t in ReportingTypes.get_list_items(): k = t.name + '_hours' dd.inject_field(SiteSummary, k, dd.DurationField(t.text, null=True, blank=True)) dd.inject_field(UserSummary, k, dd.DurationField(t.text, null=True, blank=True)) dd.inject_field(Ticket, k, dd.DurationField(t.text, null=True, blank=True)) def make_getter(t): k = t.name + '_hours' def getter(obj, ar): qs = SiteSummary.objects.filter(master=obj, year__isnull=True) d = qs.aggregate(**{k: models.Sum(k)}) n = d[k] return n return getter dd.inject_field( WorkSite, k, dd.VirtualField(dd.DurationField(t.text), make_getter(t))) if False: # removed 20181211 because useless for ts in TicketStates.get_list_items(): k = ts.get_summary_field() if k is not None: dd.inject_field(SiteSummary, k, models.IntegerField(ts.text)) def make_getter(ts): k = ts.get_summary_field() def getter(obj, ar): if ar is None: return '' qs = SiteSummary.objects.filter(master=obj) d = qs.aggregate(**{k: models.Sum(k)}) n = d[k] if n == 0: return '' sar = rt.models.tickets.TicketsBySite.request( obj, param_values=dict(state=ts, show_active=None)) # n = sar.get_total_count() url = ar.renderer.request_handler(sar) if url is None: return str(n) return E.a(str(n), href='javascript:' + url) return getter dd.inject_field( WorkSite, k, dd.VirtualField(dd.DisplayField(ts.text), make_getter(ts)))
def get_daily_field(cls, pc): Event = rt.models.cal.Event def func(fld, obj, ar): # obj is a DailyPlannerRow instance mi = ar.master_instance if mi is None: # e.g. when using DailySlave from dashboard. mi = cls.calendar_view.get_row_by_pk(ar, 0) qs = cls.get_calendar_entries(ar, obj) qs = qs.filter(event_type__planner_column=pc) qs = qs.filter(start_date=mi.date) # pv = ar.param_values # qs = Event.calendar_param_filter(qs, pv) # current_day = pv.get('date', dd.today()) # if current_day: # qs = qs.filter(start_date=current_day) # if obj is cls.model.HEADER_ROW: # qs = qs.filter(start_time__isnull=True) # else: # get_plannable_entries # if obj.start_time: # qs = qs.filter(start_time__gte=obj.start_time, # start_time__isnull=False) # if obj.end_time: # qs = qs.filter(start_time__lt=obj.end_time, # start_time__isnull=False) qs = qs.order_by('start_time') chunks = [e.obj2href(ar, cls.get_calview_div(e, ar)) for e in qs] return E.p(*join_elems(chunks)) return dd.VirtualField(dd.HtmlBox(pc.text), func)
def on_analyze(cls, site): super(TrendObservable, cls).on_analyze(site) TrendEvent = rt.models.trends.TrendEvent def w(ts): # return a getter function that returns the date of the first event # of the given trend stage. def func(obj, ar): qs = TrendEvent.objects.filter(subject=obj, trend_stage=ts) te = qs.order_by('event_date').first() if te is not None: return te.event_date return func try: for ts in rt.models.trends.TrendStage.objects.filter( subject_column=True): name = "trend_date_" + str(ts.id) vf = dd.VirtualField(dd.DateField(str(ts)), w(ts), wildcard_data_elem=True) cls.define_action(**{name: vf}) except OperationalError: pass
def setup_columns(cls): def w(ut): def func(fld, obj, ar): if isinstance(ut.role, obj): return "☑" return "" return func names = [] for ut in UserTypes.get_list_items(): name = "ut" + ut.value # vf = dd.VirtualField( # models.BooleanField(str(ut.value)), w(ut)) vf = dd.VirtualField(dd.DisplayField(str(ut.value)), w(ut)) cls.add_virtual_field(name, vf) names.append(name + ":3") # cls.column_names = "name:20 description:40 " + ' '.join(names) cls.column_names = "name:20 " + ' '.join(names)
def get_weekly_field(cls, week_day): def func(fld, obj, ar): # obj is a Plannable instance qs = cls.get_calendar_entries(ar, obj) delta_days = int(ar.rqdata.get('mk', 0) or 0) if ar.rqdata else ar.master_instance.pk # current_day = dd.today() + timedelta(days=delta_days) delta_days += int(week_day.value) - dd.today().weekday() - 1 today = dd.today(delta_days) # current_week_day = current_day + \ # timedelta(days=int(week_day.value) - current_day.weekday() - 1) qs = qs.filter(start_date=today) qs = qs.order_by('start_time') if obj is cls.model.HEADER_ROW: chunks = obj.get_header_chunks(ar, qs, today) else: chunks = obj.get_weekly_chunks(ar, qs, today) return E.table(E.tr(E.td(E.div(*join_elems(chunks)))), CLASS="fixed-table") return dd.VirtualField(dd.HtmlBox(week_day.text), func)
def get_weekday_field(cls, week_day): Event = rt.models.cal.Event def func(fld, obj, ar): # obj is a Plannable instance qs = Event.objects.all() qs = Event.calendar_param_filter(qs, ar.param_values) delta_days = int(ar.rqdata.get('mk', 0) or 0) if ar.rqdata else ar.master_instance.pk # current_day = dd.today() + timedelta(days=delta_days) current_day = dd.today(delta_days) current_week_day = current_day + \ timedelta(days=int(week_day.value) - current_day.weekday() - 1) qs = qs.filter(start_date=current_week_day) qs = qs.order_by('start_time') chunks = obj.get_weekly_chunks(ar, qs, current_week_day) return E.table(E.tr(E.td(E.div(*join_elems(chunks)))), CLASS="fixed-table") return dd.VirtualField(dd.HtmlBox(week_day.text), func)
def w(pc): verbose_name = pc.text def func(fld, week, ar): pv = ar.param_values if pv is None: return qs = Event.objects.all() qs = Event.calendar_param_filter(qs, pv) offset = int(ar.rqdata.get('mk', 0) or 0) if ar.rqdata else ar.master_instance.pk today = dd.today() current_date = dd.today(offset) target_day = week[int(pc.value) - 1] qs = qs.filter(start_date=target_day) qs = qs.order_by('start_time') chunks = [ E.p(e.obj2href(ar, e.colored_calendar_fmt(pv))) for e in qs ] pk = date2pk(target_day) daily, weekly, monthly = make_link_funcs(ar) daily_link = daily(Day(pk), str(target_day.day)) if target_day == today: daily_link = E.b(daily_link) header_items = [daily_link] header_items = gen_insert_button(cls, header_items, Event, ar, target_day) header = E.div(*header_items, align="center", CLASS="header") return E.table( E.tr(E.td(*[header, E.div(*join_elems(chunks))])), CLASS="fixed-table cal-month-cell {} {} {}".format( "current-month" if current_date.month == target_day.month else "other-month", "current-day" if target_day == today else "", "cal-in-past" if target_day < today else "")) return dd.VirtualField(dd.HtmlBox(verbose_name), func)
def w(pc, verbose_name): def func(fld, obj, ar): # obj is the DailyPlannerRow instance pv = ar.param_values qs = Event.objects.filter(event_type__planner_column=pc) qs = Event.calendar_param_filter(qs, pv) current_day = pv.get('date', dd.today()) if current_day: qs = qs.filter(start_date=current_day) if obj.start_time: qs = qs.filter(start_time__gte=obj.start_time, start_time__isnull=False) if obj.end_time: qs = qs.filter(start_time__lt=obj.end_time, start_time__isnull=False) if not obj.start_time and not obj.end_time: qs = qs.filter(start_time__isnull=True) qs = qs.order_by('start_time') chunks = [ e.obj2href(ar, e.colored_calendar_fmt(pv)) for e in qs ] return E.p(*join_elems(chunks)) return dd.VirtualField(dd.HtmlBox(verbose_name), func)
def w(rpttype, verbose_name): def func(fld, obj, ar): return obj._root2tot.get(rpttype, None) return dd.VirtualField(dd.DurationField(verbose_name), func)
def rpttype2vf(func, rpttype, verbose_name): return dd.VirtualField(dd.DurationField(verbose_name), func)
def set_upload_shortcuts(sender, **kw): """This is the successor for `quick_upload_buttons`.""" # remember that models might have been overridden. UploadType = sender.modules.uploads.UploadType for i in Shortcuts.items(): def f(obj, ar): if obj is None or ar is None: return E.div() try: utype = UploadType.objects.get(shortcut=i) except UploadType.DoesNotExist: return E.div() items = [] target = sender.modules.resolve(i.target) sar = ar.spawn_request(actor=target, master_instance=obj, known_values=dict(type=utype)) # param_values=dict(pupload_type=et)) n = sar.get_total_count() if n == 0: iar = target.insert_action.request_from(sar, master_instance=obj) btn = iar.ar2button( None, _("Upload"), icon_name="page_add", title=_("Upload a file from your PC to the server.")) items.append(btn) elif n == 1: after_show = ar.get_status() obj = sar.data_iterator[0] items.append( sar.renderer.href_button(dd.build_media_url(obj.file.name), _("show"), target='_blank', icon_name='page_go', style="vertical-align:-30%;", title=_( "Open the uploaded file in a " "new browser window"))) after_show.update(record_id=obj.pk) items.append( sar.window_action_button( sar.ah.actor.detail_action, after_show, _("Edit"), icon_name='application_form', title=_("Edit metadata of the uploaded file."))) else: obj = sar.sliced_data_iterator[0] items.append( ar.obj2html(obj, pgettext("uploaded file", "Last"))) btn = sar.renderer.action_button(obj, sar, sar.bound_action, _("All {0} files").format(n), icon_name=None) items.append(btn) return E.div(*join_elems(items, ', ')) vf = dd.VirtualField(dd.DisplayField(i.text), f) dd.inject_field(i.model_spec, i.name, vf)
def set_excerpts_actions(sender, **kw): """Installs (1) print management actions on models for which there is an excerpt type and (2) the excerpt shortcut fields defined in :class:`lino_xl.lib.excerpts.choicelists.Shortcuts`. """ # logger.info("20140401 %s.set_attest_actions()", __name__) # in case ExcerptType is overridden ExcerptType = sender.modules.excerpts.ExcerptType Excerpt = sender.modules.excerpts.Excerpt try: etypes = [(obj, obj.content_type) for obj in ExcerptType.objects.all()] except (OperationalError, ProgrammingError, UnresolvedChoice) as e: dd.logger.debug("Failed to set excerpts actions : %s", e) # Happens e.g. when the database has not yet been migrated etypes = [] for atype, ct in etypes: if ct is not None: m = ct.model_class() if m is not None: # e.g. database contains types for # models that existed before but have # been removed an = atype.get_action_name() m.define_action( **{an: CreateExcerpt(atype, six.text_type(atype))}) # dd.logger.info("Added print action to %s", m) # if atype.certifying and not issubclass(m, Certifiable): # m.define_action( # clear_printed=ClearCache()) # An attestable model must also inherit # :class:`lino.mixins.printable.BasePrintable` or some subclass # thereof. for i in Shortcuts.items(): def f(obj, ar): if ar is None: return '' if obj is None: return E.div() try: et = ExcerptType.objects.get(shortcut=i) except ExcerptType.DoesNotExist: return E.div() items = [] if True: sar = ar.spawn(ExcerptsByOwner, master_instance=obj, param_values=dict(excerpt_type=et)) n = sar.get_total_count() if n > 0: ex = sar.sliced_data_iterator[0] items.append(ar.obj2html(ex, _("Last"))) ba = sar.bound_action btn = sar.renderer.action_button(obj, sar, ba, "%s (%d)" % (_("All"), n), icon_name=None) items.append(btn) ia = getattr(obj, et.get_action_name()) btn = ar.instance_action_button(ia, _("Create"), icon_name=None) items.append(btn) else: ot = ContentType.objects.get_for_model(obj.__class__) qs = Excerpt.objects.filter(owner_id=obj.pk, owner_type=ot, excerpt_type=et) if qs.count() > 0: ex = qs[0] txt = ExcerptsByOwner.format_excerpt(ex) items.append(ar.obj2html(ex, txt)) return E.div(*join_elems(items, ', ')) vf = dd.VirtualField(dd.DisplayField(i.text), f) dd.inject_field(i.model_spec, i.name, vf)
class Mail(UserAuthored, Printable, UploadController, mixins.ProjectRelated, Controllable): class Meta: verbose_name = _("Outgoing Mail") verbose_name_plural = _("Outgoing Mails") send_mail = SendMail() date = models.DateField(verbose_name=_("Date"), help_text=""" The official date to be printed on the document. """) subject = models.CharField( _("Subject"), max_length=200, blank=True, # null=True ) body = dd.RichTextField(_("Body"), blank=True, format='html') #~ type = dd.ForeignKey(MailType,null=True,blank=True) #~ sender = dd.ForeignKey(settings.SITE.user_model, #~ verbose_name=_("Sender")) #~ related_name='outmails_by_sender', #~ blank=True,null=True) sent = models.DateTimeField(null=True, editable=False) def on_create(self, ar): self.date = settings.SITE.today() super(Mail, self).on_create(ar) #~ def disabled_fields(self,ar): #~ if not self.owner.post_as_attachment: #~ return ['body'] #~ return [] #~ @classmethod #~ def get_model_actions(self,table): #~ for x in super(Mail,self).get_model_actions(table): yield x #~ yield 'send_mail',SendMail() def get_print_language(self): if self.user is not None: return self.user.language return super(Mail, self).get_print_language() def __str__(self): return u'%s #%s' % (self._meta.verbose_name, self.pk) def get_recipients(self, rr): #~ recs = [] recs = [ str(r) for r in Recipient.objects.filter(mail=self, type=RecipientTypes.to) ] return ', '.join(recs) recipients = dd.VirtualField(dd.HtmlBox(_("Recipients")), get_recipients) def get_row_permission(self, ar, state, ba): """ Mails may not be edited after they have been sent. """ if self.sent and not ba.action.readonly: #~ logger.info("20120920 Mail.get_row_permission()") return False return super(Mail, self).get_row_permission(ar, state, ba)
# def preview(obj, ar): return obj.html or obj.text def spam(obj): """Checks if the message is spam or not """ if obj.subject.startswith("*****SPAM*****"): return True else: return False dd.inject_field('django_mailbox.Message', 'preview', dd.VirtualField(dd.HtmlBox(_("Preview")), preview)) dd.inject_field('django_mailbox.Message', 'ticket', dd.ForeignKey('tickets.Ticket', blank=True, null=True)) dd.update_field('django_mailbox.Message', 'from_header', format="plain") from .ui import * @dd.schedule_often(10) def get_new_mail(): for mb in rt.models.django_mailbox.Mailbox.objects.filter(active=True): mails = mb.get_new_mail() for mail in mails: if spam(mail): mail.spam = True
def get_monthly_field(cls, wd): Events = rt.models.cal.Events def func(fld, obj, ar): # obj is the first day of the week to show # pv = ar.param_values today = dd.today() # if pv is None: # return qs = cls.get_calendar_entries(ar, None) # qs = Event.objects.all() # qs = Event.calendar_param_filter(qs, pv) mi = ar.master_instance if mi is None: return target_day = cls.get_row_by_pk(ar, obj.pk + int(wd.value) - 1) current_month = mi.date.month nav = mi.planner # offset = ar.master_instance.pk # offset = int(ar.rqdata.get('mk', 0) or 0) if ar.rqdata else ar.master_instance.pk # current_date = dd.today(offset) # pk = offset + int(wd.value) - 1 # target_day = cls.get_row_by_pk(ar, pk) # if target_day is None: # return # target_day = week[int(wd.value)-1] qs = qs.filter(start_date=target_day.date) qs = qs.order_by('start_time') chunks = [ E.p(e.obj2href(ar, cls.get_calview_div(e, ar))) for e in qs ] # pk = date2pk(target_day) # nav.daily_view # sar = ar.spawn_request(actor=actor, param_values=ar.param_values) # rnd = settings.SITE.kernel.default_renderer # def func(day, text): # # day.navigation_mode = actor.navigation_mode # return rnd.ar2button(sar, day, text, style="", icon_name=None, title=str(day)) # daily = nav.daily_button_func(ar) daily_link = daily(target_day, str(target_day.date.day)) if target_day.date == today: daily_link = E.b(daily_link) # header_items = [daily_link] # header_items = Event.gen_insert_button(cls, header_items, ar, target_day) header_items = [daily_link] btn = ar.gen_insert_button(Events, start_date=target_day.date) if btn: header_items.append(btn) header = E.div(*header_items, align="center", CLASS="header") return E.table( E.tr(E.td(*[header, E.div(*join_elems(chunks))])), CLASS="fixed-table cal-month-cell {} {} {}".format( "current-month" if current_month == target_day.date.month else "other-month", "current-day" if target_day.date == today else "", "cal-in-past" if target_day.date < today else "")) return dd.VirtualField(dd.HtmlBox(wd.text), func)