def propagate_contact_details(self, ar=None): ContactDetailTypes = rt.models.phones.ContactDetailTypes watcher = ChangeWatcher(self) for cdt in ContactDetailTypes.get_list_items(): self.propagate_contact_detail(cdt) if ar is not None: watcher.send_update(ar)
def after_ui_save(self, ar, cw): super(Account, self).after_ui_save(ar, cw) if self.primary: mi = self.partner for o in mi.sepa_accounts.exclude(id=self.id): if o.primary: o.primary = False o.save() ar.set_response(refresh_all=True) watcher = ChangeWatcher(mi) for k in PRIMARY_FIELDS: setattr(mi, k, getattr(self, k)) mi.save() watcher.send_update(ar)
def after_ui_save(self, ar, cw): super(Account, self).after_ui_save(ar, cw) if self.primary: mi = self.partner for o in mi.sepa_accounts.exclude(id=self.id): if o.primary: o.primary = False o.save() ar.set_response(refresh_all=True) watcher = ChangeWatcher(mi) for k in PRIMARY_FIELDS: setattr(mi, k, getattr(self, k)) mi.save() watcher.send_update(ar.request)
def set_workflow_state(row, ar, state_field, target_state): """Called by workflow actions (:class:`ChangeStateAction <lino.core.workflows.ChangeStateAction>`) to perform the actual state change. """ watcher = ChangeWatcher(row) old = getattr(row, state_field.attname) target_state.choicelist.before_state_change(row, ar, old, target_state) row.before_state_change(ar, old, target_state) setattr(row, state_field.attname, target_state) row.save() target_state.choicelist.after_state_change(row, ar, old, target_state) row.after_state_change(ar, old, target_state) watcher.send_update(ar.request) row.after_ui_save(ar, watcher)
def run_from_code(self, ar, **known_values): obj = ar.selected_rows[0] related = [] for m, fk in obj._lino_ddh.fklist: # print(fk.name, m.allow_cascaded_delete, m.allow_cascaded_copy, obj) if fk.name in m.allow_cascaded_delete or fk.name in m.allow_cascaded_copy: related.append((fk, m.objects.filter(**{fk.name: obj}))) if AFTER17: fields_list = obj._meta.concrete_fields else: fields_list = obj._meta.fields if True: for f in fields_list: if not f.primary_key: if f.name not in known_values: known_values[f.name] = getattr(obj, f.name) new = obj.__class__(**known_values) # 20120704 create_instances causes fill_from_person() on a # CBSS request. else: # doesn't seem to want to work new = obj for f in fields_list: if f.primary_key: # causes Django to consider this an unsaved instance setattr(new, f.name, None) new.on_duplicate(ar, None) new.save(force_insert=True) cw = ChangeWatcher(new) for fk, qs in related: for relobj in qs: relobj.pk = None # causes Django to save a copy setattr(relobj, fk.name, new) relobj.on_duplicate(ar, new) relobj.save(force_insert=True) new.after_duplicate(ar, obj) if cw.is_dirty(): new.full_clean() new.save() return new
def after_ui_save(self, ar, cw): super(ContactDetail, self).after_ui_save(ar, cw) mi = self.partner if mi is None: return if self.primary and self.detail_type: for o in mi.phones_by_partner.exclude(id=self.id).filter( detail_type=self.detail_type): if o.primary: o.primary = False o.save() ar.set_response(refresh_all=True) k = self.detail_type.field_name if k: watcher = ChangeWatcher(mi) setattr(mi, k, self.value) watcher.send_update(ar) mi.save()
def run_from_code(self, ar, **known_values): obj = ar.selected_rows[0] related = [] for m, fk in obj._lino_ddh.fklist: # print(fk.name, m.allow_cascaded_delete, m.allow_cascaded_copy, obj) if fk.name in m.allow_cascaded_delete or fk.name in m.allow_cascaded_copy: related.append((fk, m.objects.filter(**{fk.name: obj}))) fields_list = obj._meta.concrete_fields if True: for f in fields_list: if not f.primary_key: if f.name not in known_values: known_values[f.name] = getattr(obj, f.name) new = obj.__class__(**known_values) # 20120704 create_instances causes fill_from_person() on a # CBSS request. else: # doesn't seem to want to work new = obj for f in fields_list: if f.primary_key: # causes Django to consider this an unsaved instance setattr(new, f.name, None) new.on_duplicate(ar, None) new.save(force_insert=True) cw = ChangeWatcher(new) for fk, qs in related: for relobj in qs: relobj.pk = None # causes Django to save a copy setattr(relobj, fk.name, new) relobj.on_duplicate(ar, new) relobj.save(force_insert=True) new.after_duplicate(ar, obj) if cw.is_dirty(): new.full_clean() new.save() return new
def PUT(self, **kw): # ~ dblogger.info("%s.PUT(%s)",self.__class__.__name__,kw) obj = self.get_object(kw) if obj is None: if self.allow_put2post: dblogger.info("%s:%s : PUT becomes POST", kw["alias"], kw["id"]) kw["method"] = "POST" return self.POST(**kw) else: dblogger.warning("%s:%s : PUT ignored (row does not exist)", kw["alias"], kw["id"]) return watcher = ChangeWatcher(obj) if self.PUT_special(watcher, **kw): return self.set_timestamp(kw["time"]) self.applydata(obj, kw["data"]) dblogger.info("%s:%s (%s) : PUT %s", kw["alias"], kw["id"], dd.obj2str(obj), kw["data"]) self.validate_and_save(obj) watcher.send_update(REQUEST)
def form2obj_and_save(ar, data, elem, is_new): """ Parses the data from HttpRequest to the model instance and saves it. This is used by `ApiList.post` and `ApiElement.put`, and by `Restful.post` and `Restful.put`. 20140505 : no longer used by ApiList and ApiElement, but still by Restful.* """ if is_new: watcher = None else: watcher = ChangeWatcher(elem) ar.ah.store.form2obj(ar, data, elem, is_new) elem.full_clean() if is_new or watcher.is_dirty(): pre_ui_save.send(sender=elem.__class__, instance=elem, ar=ar) elem.before_ui_save(ar) kw2save = {} if is_new: kw2save.update(force_insert=True) else: kw2save.update(force_update=True) elem.save(**kw2save) if is_new: on_ui_created.send(elem, request=ar.request) ar.success(_("%s has been created.") % obj2unicode(elem)) else: watcher.send_update(ar) ar.success(_("%s has been updated.") % obj2unicode(elem)) else: ar.success(_("%s : nothing to save.") % obj2unicode(elem)) elem.after_ui_save(ar, watcher)
def form2obj_and_save(ar, data, elem, is_new): """Parses the data from HttpRequest to the model instance and saves it This is used by `ApiList.post` and `ApiElement.put`, and by `Restful.post` and `Restful.put`. 20140505 : no longer used by ApiList and ApiElement, but still by Restful.* """ if is_new: watcher = None else: watcher = ChangeWatcher(elem) ar.ah.store.form2obj(ar, data, elem, is_new) elem.full_clean() if is_new or watcher.is_dirty(): pre_ui_save.send(sender=elem.__class__, instance=elem, ar=ar) elem.before_ui_save(ar) kw2save = {} if is_new: kw2save.update(force_insert=True) else: kw2save.update(force_update=True) elem.save(**kw2save) if is_new: on_ui_created.send(elem, request=ar.request) ar.success(_("%s has been created.") % obj2unicode(elem)) else: watcher.send_update(ar.request) ar.success(_("%s has been updated.") % obj2unicode(elem)) else: ar.success(_("%s : nothing to save.") % obj2unicode(elem)) elem.after_ui_save(ar, watcher)
def run_from_ui(self, ar, **kw): # replaces the default implementation obj = ar.selected_rows[0] # obj is a User instance client = ar.master_instance watcher = ChangeWatcher(client) coaching = pcsw.Coaching( client=client, user=obj, start_date=settings.SITE.today(), type=obj.coaching_type) coaching.full_clean() coaching.save() dd.on_ui_created.send(coaching, request=ar.request) client.client_state = pcsw.ClientStates.coached client.full_clean() client.save() watcher.send_update(ar.request) self.emit_message(ar, client) ar.success(ar.action_param_values.notify_body, alert=True, refresh_all=True, **kw)
def POST(self, **kw): # ~ dblogger.info("%s.POST(%s)",self.__class__.__name__,kw) # ~ self.prepare_data(kw['data']) obj = self.get_object(kw) if obj is None: obj = self.create_object(kw) if obj is None: dblogger.warning("%s:%s (%s) : ignored POST %s", kw["alias"], kw["id"], obj, kw["data"]) return # ~ watcher = changes.Watcher(obj,True) self.set_timestamp(kw["time"]) self.applydata(obj, kw["data"]) dblogger.info("%s:%s (%s) : POST %s", kw["alias"], kw["id"], dd.obj2str(obj), kw["data"]) self.validate_and_save(obj) dd.on_ui_created.send(sender=obj, request=REQUEST) # ~ changes.log_create(REQUEST,obj) else: watcher = ChangeWatcher(obj) dblogger.info("%s:%s : POST becomes PUT", kw["alias"], kw["id"]) self.set_timestamp(kw["time"]) self.applydata(obj, kw["data"]) dblogger.info("%s:%s (%s) : POST %s", kw["alias"], kw["id"], dd.obj2str(obj), kw["data"]) self.validate_and_save(obj) watcher.send_update(REQUEST)
def process_row(self, ar, obj, attrs): """Generate a confirmation which asks to update the given data row `obj` using the data read from the eid card (given in `attr`). """ objects, diffs = obj.get_beid_diffs(attrs) if len(diffs) == 0: return self.goto_client_response( ar, obj, _("Client %s is up-to-date") % str(obj)) oldobj = obj watcher = ChangeWatcher(obj) msg = _("Click OK to apply the following changes for %s") % obj msg = simulate_wrap(msg) msg += ' :<br/>' # UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 10: ordinal not in range(128) diffs = [str(i) for i in diffs] diffs = sorted(diffs) msg += u'\n<br/>'.join(diffs) # msg += u'\n<br/>'.join(sorted(diffs)) def yes(ar2): msg = _("%s has been saved.") % dd.obj2unicode(obj) if not dd.plugins.beid.read_only_simulate: for o in objects: o.full_clean() o.save() watcher.send_update(ar2) msg = simulate_wrap(msg) return self.goto_client_response(ar2, obj, msg) def no(ar2): return self.goto_client_response(ar2, oldobj) #~ print 20131108, msg cb = ar.add_callback(msg) cb.add_choice('yes', yes, _("Yes")) cb.add_choice('no', no, _("No")) ar.set_callback(cb)
def objects(): Company = rt.models.contacts.Company ar = rt.login(request=PseudoRequest("robin")) obj = Company(name="My pub") obj.full_clean() obj.save_new_instance(ar) cw = ChangeWatcher(obj) obj.name = "Our pub" obj.save_watched_instance(ar, cw) obj.delete_instance(ar) # this is a special fixture : it creates objects as a side effect # but does not yield them. return []
def test_comment(self, logger): """Test what happens when a comment is posted on a ticket with watchers. """ ContentType = rt.models.contenttypes.ContentType Comment = rt.models.comments.Comment Ticket = rt.models.tickets.Ticket Project = rt.models.tickets.Project Vote = rt.models.votes.Vote Message = rt.models.notify.Message User = settings.SITE.user_model create(Project, name="Project") robin = create( User, username='******', first_name="Robin", user_type=UserTypes.admin) aline = create( User, username='******', first_name="Aline", email="*****@*****.**", language='fr') obj = create( Ticket, summary="Save the world, après moi le déluge", user=robin) create(Vote, votable=obj, user=aline) self.assertEqual(Message.objects.count(), 0) url = "/api/comments/CommentsByRFC" post_data = dict() post_data[constants.URL_PARAM_ACTION_NAME] = 'submit_insert' post_data.update(short_text="I don't agree.") post_data[constants.URL_PARAM_MASTER_PK] = obj.pk ct = ContentType.objects.get_for_model(Ticket) post_data[constants.URL_PARAM_MASTER_TYPE] = ct.id # post_data[constants.URL_PARAM_REQUESTING_PANEL] = '123' response = self.client.post( url, post_data, REMOTE_USER='******', HTTP_ACCEPT_LANGUAGE='en') result = self.check_json_result( response, 'rows success message close_window') self.assertEqual(result['success'], True) self.assertEqual( result['message'], """Comment "Comment #1" has been created.""") self.assertEqual(Message.objects.count(), 1) msg = Message.objects.all()[0] # self.assertEqual(msg.message_type) self.assertEqual(msg.seen, None) self.assertEqual(msg.user, aline) expected = """Robin a commenté [ticket 1] (Save the world, """\ """après moi le déluge): I don't agree.""" self.assertEqual(expected, msg.body) # manually set created timestamp so we can test on it later. now = datetime.datetime(2016, 12, 22, 19, 45, 55) if settings.USE_TZ: now = make_aware(now) msg.created = now msg.save() settings.SERVER_EMAIL = '*****@*****.**' with capture_stdout() as out: send_pending_emails_often() out = out.getvalue().strip() print(out) expected = """send email Sender: [email protected] To: [email protected] Subject: [Django] Robin a comment? #1 (? Save the world, apr?s moi le d?luge) <body> (22/12/2016 19:45) Robin a comment? <a href="http://127.0.0.1:8000/api/tickets/Ticket/1" title="Save the world, après moi le déluge">#1</a> (Save the world, apr?s moi le d?luge): I don't agree. </body> """ self.assertEquivalent(expected, out) self.assertEqual(logger.debug.call_count, 1) logger.debug.assert_called_with( 'Send out %s summaries for %d users.', MailModes.often, 1) # logger.info.assert_called_with( # 'Notify %s users about %s', 1, 'Change by robin') Message.objects.all().delete() self.assertEqual(Message.objects.count(), 0) ar = rt.login('robin') cw = ChangeWatcher(obj) obj.priority = 200 obj.save_watched_instance(ar, cw) with capture_stdout() as out: send_pending_emails_often() out = out.getvalue().strip() # print(out) expected = "" # self.assertEquivalent(expected, out) # we do not test the output because the datetime changes. But # we actually just wanted to see if there is no # UnicodeException. We capture it in order to hide it from # test runner output. self.assertEqual(logger.debug.call_count, 2) logger.debug.assert_called_with( 'Send out %s summaries for %d users.', MailModes.often, 1)
def sync_primary_address(self, request): watcher = ChangeWatcher(self) self.sync_from_address(self.get_primary_address()) self.save() watcher.send_update(request)
def sync_primary_address(self, ar): watcher = ChangeWatcher(self) self.sync_primary_address_() self.save() watcher.send_update(ar)
def sync_primary_address(self, request): watcher = ChangeWatcher(self) self.sync_primary_address_() watcher.send_update(request)
# ~ return except Company.DoesNotExist, e: raise Exception("%s : Pharmacy or Health Insurance %s doesn't exist" % (dd.obj2str(person), pk)) # ~ dblogger.warning(u"%s : Company %s doesn't exist (please create manually in Lino).", # ~ dd.obj2str(person),pk) # ~ return qs = pcsw.ClientContact.objects.filter(client=person, type__id=nType) if qs.count() == 0: cc = pcsw.ClientContact(client=person, company_id=pk, type=pcsw.ClientContactType.objects.get(id=nType)) cc.save() dd.on_ui_created.send(sender=cc, request=REQUEST) # ~ changes.log_create(REQUEST,cc) elif qs.count() == 1: cc = qs[0] if cc.company_id != pk: watcher = ChangeWatcher(cc) cc.company_id = pk cc.save() watcher.send_update(REQUEST) # ~ watcher.log_diff(REQUEST) else: dblogger.warning(u"%s : more than 1 ClientContact (type=%r)", dd.obj2str(person), nType) def pxs2client(row, person): kw = {} store( kw, card_number=row["CARDNUMBER"], card_issuer=row.get("CARDISSUER", ""), # 20110110
def save_existing_instance(self, ar): watcher = ChangeWatcher(self) ar.ah.store.form2obj(ar, ar.rqdata, self, False) self.full_clean() self.save_watched_instance(ar, watcher)
def applydata(self, obj, data, **mapper): mapper.update(id="IDPAR", remarks="MEMO", bank_account1="COMPTE1", bank_account2="COMPTE2") ADR_applydata(obj, data) # ,**mapper) # ~ kw.update(street2kw(join_words(data['RUE'], store_date(data, obj, "DATCREA", "created") if data.has_key("LANGUE"): obj.language = isolang(data["LANGUE"]) # ~ dblogger.info("20111223 %r",data) if data.has_key("ATTRIB"): # ~ obj.newcomer = ("N" in data['ATTRIB']) # ~ obj.is_obsolete = ("A" in data['ATTRIB'] or "W" in data['ATTRIB']) obj.is_obsolete = "W" in data["ATTRIB"] if issubclass(obj.__class__, Person): # ~ mapper.update(title='ALLO') title = data.get("ALLO", "") if title in ("Herr", "Herrn", "Frau", u"Fräulein", "Madame", "Monsieur"): title = "" obj.title = title if data.has_key("FIRME"): for k, v in name2kw(data["FIRME"]).items(): setattr(obj, k, v) if data.has_key("NAME2"): setattr(obj, "addr1", data["NAME2"]) if obj.__class__ is Client: par2client(data, obj) mapper.update(gesdos_id="NB1") if data.has_key("NB2"): obj.national_id = data["NB2"] # ~ if obj.national_id: # ~ if not is_valid_ssin(obj.national_id): # ~ dblogger.info("%s : invalid SSIN %s",dd.obj2str(obj),obj.national_id) # ~ obj.national_id = None # ~ else 20121108: # ~ obj.national_id = str(obj.id) # ~ if obj.is_deprecated: # ~ obj.national_id += ' (A)' if data.has_key("ATTRIB") and "N" in data["ATTRIB"]: obj.client_state = pcsw.ClientStates.newcomer elif data["IDPRT"] == "I": obj.client_state = pcsw.ClientStates.former # ~ else: obj.client_state = pcsw.ClientStates.coached # ~ elif obj.national_id and is_valid_ssin(obj.national_id): # ~ obj.client_state = pcsw.ClientStates.coached # ~ else: # ~ obj.client_state = pcsw.ClientStates.invalid # ~ if data.has_key('NB1'): # ~ obj.gesdos_id = data['NB1'] # ~ if not obj.national_id: # ~ obj.national_id = str() if data.has_key("IDUSR"): username = settings.TIM2LINO_USERNAME(data["IDUSR"]) if username: # ~ print 20130222, username u = users.User.get_by_username(username) # ~ u = users.User.objects.get(username=username) """ typical cases: - imported client has been assigned a coach in Lino, then filled IDUSR and removed PARATTR_N in TIM """ else: u = None if obj.pk is None: # must pre-save the client here to save related # coachings obj.save() try: coaching = pcsw.Coaching.objects.get(client=obj, primary=True) except pcsw.Coaching.DoesNotExist, e: try: coaching = pcsw.Coaching.objects.get(client=obj, user=u, end_date__isnull=True) watcher = ChangeWatcher(coaching) coaching.primary = True coaching.save() watcher.send_update(REQUEST) # ~ watcher.log_diff(REQUEST) except pcsw.Coaching.DoesNotExist, e: if u is not None: coaching = pcsw.Coaching( client=obj, primary=True, user=u, type=u.coaching_type, start_date=obj.created ) coaching.save() dd.on_ui_created.send(sender=coaching, request=REQUEST) # ~ changes.log_create(REQUEST,coaching) except Exception, e: raise Exception("More than one active coaching for %r by %r" % (obj, u)) except Exception, e: raise Exception("More than one primary coaching for %r : %s" % (obj, e))