def get_request_queryset(cls, ar): mi = ar.master_instance if mi is None: return cls.model.objects.null() return cls.model.objects.filter( time__gte=mi.created, **gfk2lookup(cls.model.master, mi.owner))
def update_problems(self, obj, delete=True, fix=False): """Update the problems of this checker and the specified object. When `delete` is False, the caller is responsible for deleting any existing objects. """ Problem = rt.modules.plausibility.Problem if delete: gfk = Problem.owner qs = Problem.objects.filter(**gfk2lookup(gfk, obj, checker=self)) qs.delete() done = [] todo = [] for fixable, msg in self.get_plausibility_problems(obj, fix): if fixable: msg = "(\u2605) " + unicode(msg) if fixable and fix: done.append(msg) else: todo.append(msg) if len(todo): user = self.get_responsible_user(obj) if user is None: lang = dd.get_default_language() else: lang = user.language with translation.override(lang): msg = "\n".join([unicode(s) for s in todo]) prb = Problem(owner=obj, message=msg, checker=self, user=user) prb.full_clean() prb.save() return (todo, done)
def get_comment_header(cls, comment, ar): ch = [] if (comment.modified - comment.created).total_seconds() < 1: t = _("Created " + comment.created.strftime('%Y-%m-%d %H:%M')) else: t = _("Modified " + comment.modified.strftime('%Y-%m-%d %H:%M')) ch.append(ar.obj2html(comment, naturaltime(comment.created), title=t)) ch += [" ", _("by"), " ", ar.obj2html(comment.user, str(comment.user))] sar = cls.insert_action.request_from(ar) # print(20170217, sar) sar.known_values = dict(reply_to=comment, **gfk2lookup(comment.__class__.owner, comment.owner)) if ar.get_user().is_authenticated: btn = sar.ar2button(None, _(" Reply "), icon_name=None) # btn.set("style", "padding-left:10px") ch += [" [", btn, "]"] # ch.append(' ') # ch.append( # E.a(u"⁜", onclick="toggle_visibility('comment-{}');".format( # comment.id), title=str(_("Hide")), href="#") # ) return tostring(ch)
def get_comment_header(cls, comment, ar): ch = [] if (comment.modified - comment.created).total_seconds() < 1: t = _("Created " + comment.created.strftime('%Y-%m-%d %H:%M')) else: t = _("Modified " + comment.modified.strftime('%Y-%m-%d %H:%M')) ch.append(ar.obj2html( comment, naturaltime(comment.created), title=t)) ch += [" ", _("by"), " ", ar.obj2html(comment.user, str(comment.user))] sar = cls.insert_action.request_from(ar) # print(20170217, sar) sar.known_values = dict( reply_to=comment, **gfk2lookup( comment.__class__.owner, comment.owner)) if ar.get_user().authenticated: btn = sar.ar2button(None, _(" Reply "), icon_name=None) # btn.set("style", "padding-left:10px") ch += [" [", btn, "]"] ch.append(' ') ch.append( E.a(u"⁜", onclick="toggle_visibility('comment-{}');".format( comment.id), title=str(_("Hide")), href="#") ) return tostring(ch)
def find_similar_instances(self, limit=None, **kwargs): """Return a queryset or yield a list of similar objects. If `limit` is specified, we never want to see more than `limit` duplicates. Note that an overridden version of this method might return a list or generator instead of a Django queryset. """ qs = self.__class__.objects.filter(**kwargs) if self.pk is not None: qs = qs.exclude(pk=self.pk) parts = self.get_dupable_words(getattr(self, self.dupable_words_field)) if False: fkw = gfk2lookup(rt.models.dupable.PhoneticWord.owner, self) wq = rt.models.dupable.PhoneticWord.objects.filter(**fkw) wq = wq.filter(word__in=parts).distinct() qs = qs.annotate(num=models.Count('dupable_words__word')) # ct = ContentType.objects.get_for_model(self.__class__) # qs = qs.filter(owner_type=ct) if True: qs = qs.filter(dupable_words__word__in=parts).distinct() qs = qs.annotate(num=models.Count('dupable_words__word')) qs = qs.filter(num__gte=self.dupable_matches_required()) qs = qs.order_by('-num', 'pk') # print("20150306 find_similar_instances %s" % qs.query) if limit is None: return qs return qs[:limit]
def update_problems(self, obj, delete=True, fix=False): """Update the problems of this checker and the specified object. When `delete` is False, the caller is responsible for deleting any existing objects. """ Problem = rt.modules.plausibility.Problem if delete: gfk = Problem.owner qs = Problem.objects.filter(**gfk2lookup(gfk, obj, checker=self)) qs.delete() done = [] todo = [] for fixable, msg in self.get_plausibility_problems(obj, fix): if fixable: msg = u"(\u2605) " + str(msg) if fixable and fix: done.append(msg) else: todo.append(msg) if len(todo): user = self.get_responsible_user(obj) if user is None: lang = dd.get_default_language() else: lang = user.language with translation.override(lang): msg = '\n'.join([str(s) for s in todo]) prb = Problem(owner=obj, message=msg, checker=self, user=user) prb.full_clean() prb.save() return (todo, done)
def update_problems(self, obj=None, delete=True, fix=False): Problem = rt.models.checkdata.Problem if delete: qs = Problem.objects.filter( **gfk2lookup(Problem.owner, obj, checker=self)) qs.delete() done = [] todo = [] for fixable, msg in self.get_checkdata_problems(obj, fix): if fixable: # attn: do not yet translate # msg = string_concat(u"(\u2605) ", msg) msg = format_lazy("(\u2605) {}", msg) if fixable and fix: done.append(msg) else: todo.append(msg) if len(todo): # dd.logger.info("%s : %s", obj, todo) user = self.get_responsible_user(obj) if user is None: lang = dd.get_default_language() else: lang = user.language with translation.override(lang): msg = '\n'.join([str(s) for s in todo]) prb = Problem(owner=obj, message=msg, checker=self, user=user) prb.full_clean() prb.save() return (todo, done)
def get_filter_kw(self, ar, **kw): """ Return a dict with the "master keywords" for this table and a given `master_instance`. For example, if you have two models :class:`Book` and :class:`Author`, and a foreign key :attr:`Book.author` which points to the author of the book, and a table `BooksByAuthor` having `master_key` set to ``'author'``, then `get_filter_kw` would return a dict `{'author': <PK>}` where PK is the primary key of the action request's :attr:`master_instance <lino.core.requests.BaseRequest.master_instance>`. Another example is :class:`lino_xl.lib.tickets.EntriesBySession`, where blog entries are not directly linked to a session, but in the detail of a session we want to display a table of related blog entries. :class:`lino_xl.lib.households.SiblingsByPerson` Household members are not directly linked to a Person, but usually a Person is member of exactly one household, and in the Detail of a Person we want to display the members of that household. """ from lino.core.gfks import gfk2lookup, GenericForeignKey master_instance = ar.master_instance if self.master is None: pass # master_instance may be e.g. a lino.core.actions.EmptyTableRow # UsersWithClients as "slave" of the "table" Home elif self.master is models.Model: pass elif isinstance(self.master_field, GenericForeignKey): kw = gfk2lookup(self.master_field, master_instance, **kw) elif self.master_field is not None: if master_instance is None: if not self.master_field.null: #~ logger.info('20120519 %s.get_filter_kw()--> None',self) return # cannot add rows to this table else: master_instance = master_instance.get_typed_instance( self.master) if not isinstance(master_instance, self.master): # e.g. a ByUser table descendant called by AnonymousUser msg = "%r is not a %s (%s.master_key = '%s')" % ( master_instance.__class__, self.master, self, self.master_key) logger.warning(msg) # raise Exception(msg) # raise PermissionDenied(msg) # master_instance = None return # cannot add rows to this table kw[self.master_field.name] = master_instance # else: # msg = "20150322 Cannot handle master {0}".format(master_instance) # raise Exception(msg) return kw
def get_filter_kw(self, ar, **kw): """Return a dict with the "master keywords" for this table and a given `master_instance`. For example, if you have two models :class:`Book` and :class:`Author`, and a foreign key :attr:`Book.author` which points to the author of the book, and a table `BooksByAuthor` having `master_key` set to ``'author'``, then `get_filter_kw` would return a dict `{'author': <PK>}` where PK is the primary key of the action request's :attr:`master_instance <lino.core.requests.BaseRequest.master_instance>`. Another example is :class:`lino_xl.lib.tickets.models.EntriesBySession`, where blog entries are not directly linked to a session, but in the detail of a session we want to display a table of related blog entries. :class:`lino_xl.lib.households.models.SiblingsByPerson` Household members are not directly linked to a Person, but usually a Person is member of exactly one household, and in the Detail of a Person we want to display the members of that household. """ from lino.core.gfks import gfk2lookup, GenericForeignKey master_instance = ar.master_instance if self.master is None: pass # master_instance may be e.g. a lino.core.actions.EmptyTableRow # UsersWithClients as "slave" of the "table" Home elif self.master is models.Model: pass elif isinstance(self.master_field, GenericForeignKey): kw = gfk2lookup(self.master_field, master_instance, **kw) elif self.master_field is not None: if master_instance is None: if not self.master_field.null: #~ logger.info('20120519 %s.get_filter_kw()--> None',self) return # cannot add rows to this table else: master_instance = master_instance.get_typed_instance( self.master) if not isinstance(master_instance, self.master): # e.g. a ByUser table descendant called by AnonymousUser msg = "%r is not a %s (%s.master_key = '%s')" % ( master_instance.__class__, self.master, self, self.master_key) logger.warning(msg) # raise Exception(msg) # raise PermissionDenied(msg) # master_instance = None return # cannot add rows to this table kw[self.master_field.name] = master_instance # else: # msg = "20150322 Cannot handle master {0}".format(master_instance) # raise Exception(msg) return kw
def get_filter_kw(self, ar, **kw): Event = rt.models.cal.Event enr = ar.master_instance if enr is None: return None for k, v in gfk2lookup(Event.owner, enr.course).items(): kw['event__' + k] = v kw.update(partner=enr.pupil) return super(PresencesByEnrolment, self).get_filter_kw(ar, **kw)
def get_invoicings(self, **kwargs): """Get a queryset with the invoicings which point to this enrolment. This is deprecated. Preferred way is to use :attr:`invoicings`. """ item_model = dd.plugins.invoicing.item_model # item_model = rt.modules.sales.InvoiceItem kwargs.update(gfk2lookup(item_model.invoiceable, self)) return item_model.objects.filter(**kwargs)
def create_message(cls, user, owner=None, **kwargs): 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)
def get_filter_kw(self, ar, **kw): """ Return a dict with the "master keywords" for this table and a given `master_instance`. :class:`lino.modlib.tickets.models.EntriesBySession` Blog Entries are not directly linked to a Session, but in the Detail of a Session we want to display a table of related blog entries. :class:`lino_xl.lib.households.models.SiblingsByPerson` Household members are not directly linked to a Person, but usually a Person is member of exactly one household, and in the Detail of a Person we want to display the members of that household. """ from lino.core.gfks import gfk2lookup, GenericForeignKey master_instance = ar.master_instance if self.master is None: pass # master_instance may be e.g. a lino.core.actions.EmptyTableRow # UsersWithClients as "slave" of the "table" Home elif self.master is models.Model: pass elif isinstance(self.master_field, GenericForeignKey): kw = gfk2lookup(self.master_field, master_instance, **kw) elif self.master_field is not None: if master_instance is None: if not self.master_field.null: # ~ logger.info('20120519 %s.get_filter_kw()--> None',self) return # cannot add rows to this table else: master_instance = master_instance.get_typed_instance(self.master) if not isinstance(master_instance, self.master): # e.g. a ByUser table descendant called by AnonymousUser msg = "%r is not a %s (%s.master_key = '%s')" % ( master_instance.__class__, self.master, self, self.master_key, ) logger.warning(msg) # raise Exception(msg) # raise PermissionDenied(msg) # master_instance = None return # cannot add rows to this table kw[self.master_field.name] = master_instance # else: # msg = "20150322 Cannot handle master {0}".format(master_instance) # raise Exception(msg) return kw
def create_message(cls, user, owner=None, **kwargs): 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)
def set_value_in_object(self, request, obj, value): # dd.logger.info("20170508 set_value_in_object(%s, %s)", obj, value) # if value is None: # raise Exception("20170508") if value is not None: Interest = rt.models.topics.Interest if Interest.objects.filter(**gfk2lookup( Interest.owner, obj, topic=value)).count() == 0: try: create_row(Interest, topic=value, owner=obj) except Exception as e: dd.logger.warning("20170508 ignoring %s", e) return obj
def get_filter_kw(cls, ar, **kw): mi = ar.master_instance if mi is None: return None Mention = rt.models.comments.Mention mkw = gfk2lookup(Mention.owner, mi) mentions = Mention.objects.filter(**mkw).values_list('comment_id', flat=True) # mentions = [o.comment_id for o in Mention.objects.filter(**mkw)] # print(mkw, mentions) # return super(CommentsByMentioned, cls).get_filter_kw(ar, **kw) kw.update(id__in=mentions) return kw
def full_clean(self): #raise Exception("20180124") if self.date_issued is None: Event = rt.models.cal.Event flt = gfk2lookup(Event.owner, self.enrolment.course) qs = Event.objects.filter(**flt).order_by('-start_date') qs = qs.filter(state__in=EntryStates.filter(fixed=True)) ce = qs.first() if ce is None: self.date_issued = dd.today() else: self.date_issued = ce.start_date super(Reminder, self).full_clean()
def run_from_ui(self, ar, fix=None): if fix is None: fix = self.fix_them Problem = rt.modules.plausibility.Problem gfk = Problem.owner checkers = get_checkable_models()[self.model] for obj in ar.selected_rows: assert isinstance(obj, self.model) qs = Problem.objects.filter(**gfk2lookup(gfk, obj)) qs.delete() for chk in checkers: chk.update_problems(obj, False, fix) ar.set_response(refresh=True)
def create_message(cls, user, owner=None, **kwargs): """Create a message unless that user has already been notified about that object. """ fltkw = gfk2lookup(cls.owner, owner) qs = cls.objects.filter( user=user, seen__isnull=True, **fltkw) if not qs.exists(): obj = cls(user=user, owner=owner, **kwargs) obj.full_clean() obj.save() if settings.SITE.use_websockets: obj.send_browser_message(user)
def notify(cls, ar, owner, user, message): """Create a notification unless that user has already been notified about that object. """ fltkw = gfk2lookup(cls.owner, owner) qs = cls.objects.filter(user=user, seen__isnull=True, **fltkw) if not qs.exists(): # create a notification object and send email obj = cls(user=user, owner=owner, message=message) obj.full_clean() obj.save() obj.send_email(ar)
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)
def run_from_ui(self, ar, **kw): Event = rt.models.cal.Event gfk = Event._meta.get_field('owner') states = EntryStates.filter(fixed=False) for obj in ar.selected_rows: qs = Event.objects.filter( **gfk2lookup(gfk, obj, state__in=states)) def ok(ar2): for e in qs: self.run_on_event(ar, e) fmt = obj.get_date_formatter() txt = ', '.join([fmt(e.start_date) for e in qs]) ar.confirm(ok, _("Update presences for {} events: {}").format( qs.count(), txt))
def run_from_ui(self, ar, fix=None): if fix is None: fix = self.fix_them Problem = rt.modules.plausibility.Problem # print(20150327, ar.selected_rows) for obj in ar.selected_rows: assert isinstance(obj, Problem) chk = obj.checker owner = obj.owner # not tested: what happens if the following deletes # another obj from selected_rows? qs = Problem.objects.filter( **gfk2lookup(Problem.owner, owner, checker=chk)) qs.delete() chk.update_problems(owner, False, fix) ar.set_response(refresh_all=True)
def run_from_ui(self, ar, fix=None): if fix is None: fix = self.fix_them Problem = rt.models.checkdata.Problem # print(20150327, ar.selected_rows) for obj in ar.selected_rows: assert isinstance(obj, Problem) chk = obj.checker owner = obj.owner if owner is None: # A problem where owner is None means that the owner # has been deleted. obj.delete() else: qs = Problem.objects.filter( **gfk2lookup(Problem.owner, owner, checker=chk)) qs.delete() chk.update_problems(owner, False, fix) ar.set_response(refresh_all=True)
def update_missing_rate(self, ar): Guest = rt.models.cal.Guest Event = rt.models.cal.Event # flt = Event.objects.filter( # gfk2lookup(Event.owner, self.course)) flt = {'event__'+k: v for k, v in gfk2lookup(Event.owner, self.course).items()} flt.update(partner=self.pupil) total = Guest.objects.filter(**flt).count() if total: missing = Guest.objects.filter( state__in=(GuestStates.missing, GuestStates.excused), **flt).count() self.missing_rate = myround(Decimal(missing*100) / total) else: self.missing_rate = ZERO self.full_clean() self.save() ar.success(refresh=True)
def update_dupable_words(self, really=True): """Update the phonetic words of this row.""" # Excerpt from Django docs: "A related object set can be # replaced in bulk with one operation by assigning a new # iterable of objects to it". But only when the relation is # nullable... if settings.SITE.loading_from_dump: return PhoneticWord = rt.models.dupable.PhoneticWord qs = PhoneticWord.objects.filter( **gfk2lookup(PhoneticWord.owner, self)).order_by('id') existing = [o.word for o in qs] wanted = list( self.get_dupable_words(getattr(self, self.dupable_words_field))) if existing == wanted: return if really: qs.delete() for w in wanted: PhoneticWord(word=w, owner=self).save() return _("Must update phonetic words.")
def for_obj(cls, obj, **kwargs): """Return a queryset of :class:`Star` instances for the given database object. """ return cls.objects.filter(**gfk2lookup(cls.owner, obj, **kwargs))
def controlled_rows(self, model, **kwargs): gfk = self._meta.get_field('owner') kwargs = gfk2lookup(gfk, self, **kwargs) return model.objects.filter(**kwargs)
def get_invoicings(self, **kwargs): item_model = dd.plugins.invoicing.item_model # item_model = rt.models.sales.InvoiceItem kwargs.update(gfk2lookup(item_model.invoiceable, self)) return item_model.objects.filter(**kwargs)
def assert_check(obj, expected): qs = Problem.objects.filter(**gfk2lookup(Problem.owner, obj)) got = '\n'.join([p.message for p in qs]) self.assertEqual(got, expected)
def load_dls(self, row, **kw): pk = row.iddls.strip() # if not row.idpin.strip(): # return if pk.startswith('E'): team = self.eupen pk = int(pk[1:]) elif pk.startswith('S'): team = self.stvith pk = int(pk[1:]) + 1000000 # Cannot import duplicate session 104877 if not pk: return if pk in self.imported_sessions: dd.logger.warning("Cannot import duplicate session %s", pk) return idusr = row.idusr.strip() u = self.get_user(idusr) if u is None: dd.logger.warning( "Cannot import session %s because there is no user %s", pk, idusr) return if u.team != team: u1 = u # idusr += '@' + str(team.pk) idusr += '@' + str(team) try: u = User.objects.get(username=idusr) except User.DoesNotExist: u = create(User, username=idusr, first_name=u1.first_name, team=team, user_type=u1.user_type) dd.logger.info("Created new user %s", u) kw.update(user=u) kw.update(id=pk) iddla = row.iddla.strip() if iddla: dla = self.get_event_type(iddla) kw.update(event_type=dla) v = row.etat.strip() if v: kw.update(state=self.get_event_state(v)) # if row.idprj.strip(): # kw.update(project_id=int(row.idprj)) # kw.update(partner_id=PRJPAR.get(int(row.idprj),None)) idpar = row.idpar.strip() if not idpar: dd.logger.info("Missing IdPar in DLS:%s", pk) return try: course = Course.get_by_ref(idpar) except Course.DoesNotExist: course = Course(state=CourseStates.draft, ref=idpar, line=self.other_groups) dd.logger.info("Created new therapy %s", course) yield course self.imported_sessions.add(pk) kw.update(**gfk2lookup(Event.owner, course)) kw.update(summary=row.nb.strip()) kw.update(start_date=row.date) def set_time(kw, fldname, v): v = v.strip() if not v: return if v == '24:00': v = '0:00' kw[fldname] = v set_time(kw, 'start_time', row.von) set_time(kw, 'end_time', row.bis) obj = Event(**kw) yield obj
def get_invoicings(self, **kwargs): # deprecated. use invoicings instead. item_model = dd.plugins.invoicing.item_model # item_model = rt.models.sales.InvoiceItem kwargs.update(gfk2lookup(item_model.invoiceable, self)) return item_model.objects.filter(**kwargs)
def for_obj_and_master(cls, obj, master, **kwargs): kwargs = gfk2lookup(cls.owner, obj, **kwargs) kwargs = gfk2lookup(cls.master, master, **kwargs) return cls.objects.filter(**gfk2lookup(cls.owner, obj, **kwargs))
def for_master(cls, master, **kwargs): return cls.objects.filter(**gfk2lookup(cls.master, master, **kwargs))
def get_parent_star_from_model(cls, master_model, child, ar): # lookup a parent star when all you know is the model of the parent kw = gfk2lookup(Star.owner, child, user=ar.get_user()) return cls.for_master_model(master_model, **kw)
def load_dls(self, row, **kw): pk = row.iddls.strip() # if not row.idpin.strip(): # return if pk.startswith('E'): team = self.eupen pk = int(pk[1:]) elif pk.startswith('S'): team = self.stvith pk = int(pk[1:]) + 1000000 # Cannot import duplicate session 104877 if not pk: return if pk in self.imported_sessions: dd.logger.warning( "Cannot import duplicate session %s", pk) return idusr = row.idusr.strip() u = self.get_user(idusr) if u is None: dd.logger.warning( "Cannot import session %s because there is no user %s", pk, idusr) return if u.team != team: u1 = u # idusr += '@' + str(team.pk) idusr += '@' + str(team) try: u = User.objects.get(username=idusr) except User.DoesNotExist: u = create( User, username=idusr, first_name=u1.first_name, team=team, user_type=u1.user_type) dd.logger.info("Created new user %s", u) kw.update(user=u) kw.update(id=pk) iddla = row.iddla.strip() if iddla: dla = self.get_event_type(iddla) kw.update(event_type=dla) v = row.etat.strip() if v: kw.update(state=self.get_event_state(v)) # if row.idprj.strip(): # kw.update(project_id=int(row.idprj)) # kw.update(partner_id=PRJPAR.get(int(row.idprj),None)) idpar = row.idpar.strip() if not idpar: dd.logger.info("Missing IdPar in DLS:%s", pk) return try: course = Course.get_by_ref(idpar) except Course.DoesNotExist: course = Course( state=CourseStates.draft, ref=idpar, line=self.other_groups) dd.logger.info("Created new therapy %s", course) yield course self.imported_sessions.add(pk) kw.update(**gfk2lookup(Event.owner, course)) kw.update(summary=row.nb.strip()) kw.update(start_date=row.date) def set_time(kw, fldname, v): v = v.strip() if not v: return if v == '24:00': v = '0:00' kw[fldname] = v set_time(kw, 'start_time', row.von) set_time(kw, 'end_time', row.bis) obj = Event(**kw) yield obj
def assert_check(obj, *expected): qs = Problem.objects.filter(**gfk2lookup(Problem.owner, obj)) got = tuple(p.message for p in qs) self.assertEqual(got, expected)