Exemple #1
0
    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,))
Exemple #2
0
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
Exemple #3
0
    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)
Exemple #4
0
    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.")
Exemple #5
0
    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))
Exemple #6
0
    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))
Exemple #7
0
    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)
Exemple #8
0
    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()
Exemple #9
0
    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()))
Exemple #10
0
    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.")