def get(self): login_user = get_login_user() format = self.request.get("format", "JSON") if format not in ['JSON','yaml']: logging.Critical("Unknown format for export: %s" % (format)) self.error(500) return # not logged in if not login_user: self.redirect('/login') return if self.request.get('attic',"") == 'True': attic = True else: attic = False # shall a specific dataset be exported? key = self.request.get("key", None) logging.info("export format: attic: %d user: %s admin: %d" % (attic,user.nickname(),users.is_current_user_admin())) self.response.headers['Content-Type'] = 'text/plain' # Administrator exports everything contacts = [] if users.is_current_user_admin(): if key: con = Contact.get(key) if con: contacts.append(encode_contact(con, include_attic=attic, signed_in=True, is_admin=True)) else: q_con = Contact.all() for con in q_con: contacts.append(encode_contact(con, include_attic=attic, signed_in=True, is_admin=True)) else: login_user = get_login_user(user) if key: con = Contact.get(key) if con: contacts.append(encode_contact(con, include_attic=attic, signed_in=True, is_admin=True)) else: # export everything this user can see for ckey in visible_contacts(login_user, include_attic=attic): con = Contact.get(ckey) contacts.append(encode_contact(con, include_attic=attic, me=login_user.me)) self.response.headers['Content-Disposition'] = "attachment; filename=address_export.json" if format == 'JSON': self.response.headers['Content-Type'] = "text/plain" self.response.out.write(json.dumps(contacts,indent=2)) else: self.response.headers['Content-Type'] = "text/yaml" self.response.out.write(yaml.dump(contacts,))
def upcoming_birthdays(login_user): """Returns a dictionary with names, nicknames and birthdays of the login_user's contacts""" res = [] daterange_from = datetime.today() - timedelta(days=5) daterange_to = datetime.today() + timedelta(days=14) # Convert to fuzzydate and then to int (that's how it is stored in the db). # Year is least important fuzzydate_from = FuzzyDate(day=daterange_from.day, month=daterange_from.month).to_int() fuzzydate_to = FuzzyDate(day=daterange_to.day, month=daterange_to.month).to_int() if fuzzydate_from > fuzzydate_to: # end-of-year turnover fuzzydate_to_1 = 12310000 fuzzydate_from_1 = 1010000 else: fuzzydate_from_1 = fuzzydate_from fuzzydate_to_1 = fuzzydate_to logging.debug("Birthday search from: %d to %d OR %d to %d" % (fuzzydate_from,fuzzydate_to_1,fuzzydate_from_1,fuzzydate_to)) # now find the ones with birthdays in the range for con in Contact.all().filter("owned_by =", login_user): # skip companies if con.class_name() != "Person": continue if ((con.birthday.to_int() > fuzzydate_from and con.birthday.to_int() <= fuzzydate_to_1) or (con.birthday.to_int() > fuzzydate_from_1 and con.birthday.to_int() <= fuzzydate_to)): jubilee = {} # change birthday encoding from yyyy-mm-dd to dd Month jubilee['birthday'] = "%d %s" % (con.birthday.get_day(), calendar.month_name[con.birthday.get_month()]) jubilee['name'] = con.name jubilee['nickname'] = con.nickname if con.nickname else "" res.append(jubilee) return res
def deattic_contact(self, login_user=None, template_values={}): key = self.request.get("key", "") contact = Contact.get(key) assert contact, "Object key: %s is not a Contact" % (key) # access check assert contact.owned_by.key() == login_user.key(), "User %s cannot manipulate %s" % (login_user.user.nickname(),str(contact.key())) logging.debug("ContactDeattic: %s key: %s" % (contact.name,key)) contact.attic = False; contact.put(); update_index(contact) self.redirect('/editcontact?key=%s' % key)
def get(self): """Function is called by cron to build a contact index Call with a key to build index for this entity. """ if not users.is_current_user_admin(): logging.critical("UpdateIndex called by non-admin") self.error(500) return key = self.request.get("key", None) logging.info("Update index tables.") if key: con = Contact.get(Key(key)) if con: update_index(con) # update dependant take2 entries for t2 in Take2.all().filter("contact_ref =", con): update_index(t2) # update parent login_user user = LoginUser.all().filter("me =", con).get() if user: update_index(user) return else: t2 = Take2.get(Key(key)) if t2: update_index(t2) return logging.info("Could not find key: %s" % (key)) return # Go through the tables which contribute to the index for table in [LoginUser,Contact,Address]: batch = [] for obj in table.all(): res = update_index(obj, batch=True) if res: batch.extend(res) # bulk db operation db.put(batch) logging.info("%d updates." % (len(batch))) self.response.headers['Content-Type'] = "text/plain" self.response.out.write("/index done.")
def get(self, login_user=None, template_values={}): contact_key = self.request.get("key", None) assert contact_key con = Contact.get(contact_key) # access rights check if not write_access(con,login_user): self.error(500) return contact = encode_contact(con, login_user, include_attic=True) # render edit page template_values['contact'] = contact path = os.path.join(os.path.dirname(__file__), 'take2edit.html') self.response.out.write(template.render(path, template_values))
def get(self, login_user=None, template_values={}): """Function is called to update a take2 object or a contact. The function prepares the data for the form. After the form is completed, a save function will store the new data.""" instance = self.request.get("instance", "") instance_list = instance.split(",") contact_ref = self.request.get("contact_ref", None) # contact_ref points to the person to which the take2 entries in this form # belong to. assert contact_ref, "No contact_ref / key received." contact = Contact.get(contact_ref) # access rights check if not write_access (contact, login_user): self.error(500) return template_values['titlestr'] = "Address book entry for %s %s" % (contact.name, contact.lastname) # # Use beans to prepare form data # for (bean_name,bean_class) in (('Person',PersonBean),('Email',EmailBean),('Mobile',MobileBean), ('Address',AddressBean),('Web',WebBean),('Other',OtherBean)): if bean_name in instance_list: key = self.request.get('%s_key' % bean_name, None) if not key and not bean_name == 'Person': # We simply treat this as a new object obj = bean_class.new(contact_ref) else: obj = bean_class.load(key) template_values.update(obj.get_template_values()) # instances as list and as concatenated string template_values['instance_list'] = instance_list template_values['instance'] = instance template_values['contact_ref'] = contact_ref template_values['action'] = 'edit' path = os.path.join(os.path.dirname(__file__), 'take2form.html') self.response.out.write(template.render(path, template_values))
def attic_contact(self, login_user=None, template_values={}): key = self.request.get("key", "") contact = Contact.get(key) assert contact, "Object key: %s is not a Contact" % key # access check if not write_access(contact, login_user): self.error(500) return logging.debug("ContactAttic: %s key: %s" % (contact.name,key)) contact.attic = True; contact.put(); update_index(contact) # if the contact had a backwards refrence, direkt to the middleman if contact.middleman_ref: key = str(contact.middleman_ref.key()) self.redirect('/editcontact?key=%s' % key)
def post(self): """Function is called asynchronously to import data sets to the DB and delete existing data. """ login_user = LoginUser.get(self.request.get("login_user", None)) status = memcache.get('import_status') if not status: logging.critical("Failed to retrieve import status from memcache.") self.error(500) return data = memcache.get('import_data') if not data: logging.critical("Failed to retrieve import data from memcache.") self.error(500) return logging.info("Retrieved %d bytes for processing. user=%s" % (len(data),login_user.me.name) ) memcache.set('import_status', "Parsing import data.", time=10) format=self.request.get("format", None) if format == 'JSON': dbdump = json.loads(data) else: dbdump = yaml.load(data) # purge DB logging.info("Import task starts deleting data...") contact_entries = db.Query(Contact,keys_only=True) contact_entries.filter("owned_by =", login_user) count = 0 delete_contacts = [] for c in contact_entries: # delete all dependent data q_t = db.Query(Take2,keys_only=True) q_t.filter("contact_ref =", c) db.delete(q_t) q_i = db.Query(Search,keys_only=True) q_i.filter("contact_ref =", c) db.delete(q_i) count = count +1 memcache.set('import_status', "Deleting data: %d deleted." % (count), time=3) # remember for bulk delete except the one which is the login_user's Person if c != login_user.me: delete_contacts.append(c) db.delete(delete_contacts) logging.info("Import task deleted %d contact datasets" % (count)) # dictionary will be filled with a reference to the freshly created person # key using the former key as stored in the dbdump. Needed later for resolving # the owned by references. old_key_to_new_key = {} link_to_references = [] take2_entries = [] count = 0.0 for contact in dbdump: memcache.set('import_status', "Importing data: %3.0f%% done." % ((count/len(dbdump))*100.0), time=3) logging.debug("Import type: %s name: %s id: %s attic: %s" % (contact['type'], contact['name'] if 'name' in contact else '<no name>', contact['id'] if 'id' in contact else '<no id>', contact['attic'] if 'attic' in contact else '<no attic flag>')) if contact['type'] == "person": entry = Person(name=contact['name']) if 'lastname' in contact: entry.lastname = lastname=contact['lastname'] if 'birthday' in contact: year,month,day = contact['birthday'].split('-') entry.birthday = FuzzyDate(day=int(day),month=int(month),year=int(year)) if 'nickname' in contact: entry.nickname = contact['nickname'] if contact['type'] == "company": entry = Company(name=contact['name']) # importer owns all the data entry.owned_by = login_user if 'attic' in contact: entry.attic = contact['attic'] if 'timestamp' in contact: dt,us= contact['timestamp'].split(".") entry.timestamp = datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S") entry.put() # remember the key from the imported file for later dependency resolve if 'key' in contact: old_key_to_new_key[contact['key']] = entry.key() count = count+1 # check for all take2 objects for classname in ['email','link','web','address','mobile','other']: if classname in contact: for m in contact[classname]: obj = None if classname == 'mobile': obj = Mobile(mobile=m['mobile'], contact_ref=entry) if classname == 'email': obj = Email(email=m['email'], contact_ref=entry) if classname == 'web': if not m['web'].startswith("http://"): m['web'] = 'http://'+m['web'] obj = Web(web=m['web'], contact_ref=entry) if classname == 'other': # look for existing tag in DB tag = OtherTag.all().filter("tag =", m['what']).get() if not tag: tag = OtherTag(tag=m['what']) tag.put() obj = Other(tag=tag, text=m['text'], contact_ref=entry) if classname == 'link': # save the link_to key from the imported data in the link_to # property for rater resolve link_to_references.append((entry.key(),m['link_to'])) if classname == 'address': obj = Address(adr=m['adr'], contact_ref=entry) if 'location_lat' in m and 'location_lon' in m: obj.location = db.GeoPt(lat=float(m['location_lat']),lon=float(m['location_lon'])) if 'landline_phone' in m: obj.landline_phone = m['landline_phone'] if 'country' in m and m['country'] != "": country = Country.all().filter("country =", m['country']).get() # If country name is not in DB it is added if not country: country = Country(country=m['country']) country.put() obj.country = country.key() if obj: # common fields if 'timestamp' in m: dt,us= m['timestamp'].split(".") obj.timestamp = datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S") if 'attic' in m: obj.attic = m['attic'] take2_entries.append(obj) memcache.set('import_status', "Store dependent entries.", time=30) # # Resolve (if possible) the reference of the LoginUser to his/her own Person entry # for t2 in take2_entries: if t2.class_name() == "Email": if t2.email == login_user.user.email(): # throw away existing login_user Person login_user.me.delete() login_user.put() login_user.me = t2.contact_ref login_user.put() logging.info("Resolved LoginUsers Person: %s using email: %s" % (t2.contact_ref.name, t2.email)) # # Back references to people # for parent,child_old_key in link_to_references: # find child's new key key = old_key_to_new_key[child_old_key] # update child with back reference child = Contact.get(key) child.middleman_ref = parent child.put() # # Bulk store new entries # logging.info("Import task added %d contacts. Now store their %d dependent datasets" % (count,len(take2_entries))) db.put(take2_entries) logging.info("Import task done.") # make sure that all indices have to be re-built memcache.flush_all()
def post(self, login_user=None, template_values={}): instance = self.request.get("instance", "") instance_list = instance.split(",") contact_ref = self.request.get("contact_ref", None) # contact_ref points to the person to which the take2 entries in this form # belong to. # The only case that it won't exist in the input form is if a new contact # (Person) is saved. contact = None if contact_ref: contact = Contact.get(contact_ref) # access rights check if not write_access (contact, login_user): self.error(500) return template_values['titlestr'] = "Address book entry for %s %s" % (contact.name, contact.lastname) else: # otherwise for the login_user template_values['titlestr'] = "New address book entry for %s %s" % (login_user.me.name, login_user.me.lastname) template_values['errors'] = [] if 'Person' in instance_list: person = PersonBean.edit(login_user,self.request) template_values.update(person.get_template_values()) err = person.validate() if not err: person.put() else: template_values['errors'].extend(err) # This is now the person to which the take2 data relates contact = person.get_entity() # go through all take2 types for (bean_name,bean_class) in (('Email',EmailBean),('Mobile',MobileBean),('Address',AddressBean), ('Web',WebBean),('Other',OtherBean)): if bean_name in instance_list: obj = bean_class.edit(contact, self.request) template_values.update(obj.get_template_values()) err = obj.validate() if not err: obj.put() else: # If the object is there in conjunction with the person that # means it's just not filled in. We save only the person, that's fine if 'Person' in instance_list: continue template_values['errors'].extend(err) # if errors happened, re-display the form if template_values['errors']: template_values['instance_list'] = instance_list template_values['instance'] = instance template_values['contact_ref'] = contact_ref path = os.path.join(os.path.dirname(__file__), 'take2form.html') self.response.out.write(template.render(path, template_values)) return self.redirect('/editcontact?key=%s' % str(contact.key()))
def get(self): if not users.is_current_user_admin(): logging.critical("UpdateIndex called by non-admin") self.error(500) return fix = True if self.request.get("fix", "False") == "True" else False # look for LoginUser with invalid Person attached logging.info("Check LoginUser") err = False for obj in LoginUser.all(): try: if not obj.me: logging.critical("LoginUser %d has no Person attached" % ((obj.key().id()))) err = True except db.ReferencePropertyResolveError: logging.critical("LoginUser %d has invalid Person reference" % ((obj.key().id()))) err = True if err: # check for dependent datasets count = Contact.all().filter("owned_by =", obj).count() logging.critical("LoginUser %d has %d dependant datasets" % (obj.key().id(),count)) if fix: obj.delete() logging.info("%d deleted" % obj.key().id()) err = False logging.info("Check Contact") err = False for obj in Contact.all(): try: if not obj.owned_by: logging.critical("Contact '%s' %d has no reference to owner" % (obj.name,obj.key().id())) err = True except db.ReferencePropertyResolveError: logging.critical("Contact '%s' %d has invalid reference to owner" % (obj.name,obj.key().id())) count = LoginUser.all().filter("me =", obj).count() if count: logging.critical("... but owner has reference!") err = True if err: # check for dependent datasets count = Take2.all().filter("contact_ref =", obj).count() logging.critical("Contact '%s' has %d dependent datasets" % (obj.name, count)) if fix: obj.delete() logging.info("%d deleted" % obj.key().id()) err = False logging.info("Check Take2") err = False for obj in Take2.all(): try: if not obj.contact_ref: logging.critical("Take2 has no reference to owner %s" % (obj.key().id())) err = True except db.ReferencePropertyResolveError: logging.critical("Take2 has invalid reference to owner %s" % (obj.key().id())) err = True if err: if fix: obj.delete() logging.info("%d deleted" % obj.key().id()) # location in address shall be set to default if obj.class_name() == 'Address' and not obj.location: logging.error("Address has null location %s. Fixed." % (obj.key().id())) obj.location=db.GeoPt(lon=0.0, lat=0.0) obj.put() err = False logging.info("Check SearchIndex") err = False for obj in SearchIndex.all(): try: if not obj.contact_ref: logging.critical("SearchIndex %d has no reference to owner" % (obj.key().id())) err = True except db.ReferencePropertyResolveError: logging.critical("SearchIndex %d has invalid reference to owner" % (obj.key().id())) err = True if err: if fix: obj.delete() logging.info("%d deleted" % obj.key().id()) err = False logging.info("Check GeoIndex") err = False for obj in GeoIndex.all(): try: if not obj.contact_ref: logging.critical("GeoIndex %d has no reference to owner" % (obj.key().id())) err = True except db.ReferencePropertyResolveError: logging.critical("GeoIndex %d has invalid reference to owner" % (obj.key().id())) err = True if err: if fix: obj.delete() logging.info("%d deleted" % obj.key().id()) err = False self.response.headers['Content-Type'] = "text/plain" self.response.out.write("/fix done.")