def get(self): if self.config.read_auth_key_required and not (self.auth and self.auth.read_permission): self.info(403, message="Missing or invalid authorization key", style="plain") return pfif_version = self.params.version # Note that self.request.get can handle multiple IDs at once; we # can consider adding support for multiple records later. record_id = self.request.get("id") if not record_id: self.info(400, message="Missing id parameter", style="plain") return person = model.Person.get(self.repo, record_id, filter_expired=False) if not person: self.info(400, message="No person record with ID %s" % record_id, style="plain") return notes = model.Note.get_by_person_record_id(self.repo, record_id) notes = [note for note in notes if not note.hidden] self.response.headers["Content-Type"] = "application/xml" records = [pfif_version.person_to_dict(person, person.is_expired)] note_records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) utils.optionally_filter_sensitive_fields(note_records, self.auth) pfif_version.write_file(self.response.out, records, lambda p: note_records) utils.log_api_action(self, ApiActionLog.READ, len(records), len(notes))
def get(self): if self.config.search_auth_key_required and not ( self.auth and self.auth.search_permission): self.info(403, message='Missing or invalid authorization key', style='plain') return pfif_version = self.params.version # Retrieve parameters and do some sanity checks on them. record_id = self.request.get('id') query_string = self.request.get('q') max_results = min(self.params.max_results or 100, HARD_MAX_RESULTS) results = [] if record_id: # Search by record ID (always returns just 1 result or nothing). person = model.Person.get(self.repo, record_id) if person: results = [person] elif query_string: # Search by query words. if self.config.external_search_backends: query = TextQuery(query_string) results = external_search.search( self.repo, query, max_results, self.config.external_search_backends) # External search backends are not always complete. Fall back to # the original search when they fail or return no results. if not results: if config.get('enable_fulltext_search'): results = full_text_search.search(self.repo, query_string, max_results) else: results = indexing.search(self.repo, TextQuery(query_string), max_results) else: self.info(400, message='Neither id nor q parameter specified', style='plain') records = [pfif_version.person_to_dict(result) for result in results] utils.optionally_filter_sensitive_fields(records, self.auth) # Define the function to retrieve notes for a person. def get_notes_for_person(person): notes = model.Note.get_by_person_record_id( self.repo, person['person_record_id']) notes = [note for note in notes if not note.hidden] records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) return records self.response.headers[ 'Content-Type'] = 'application/xml; charset=utf-8' pfif_version.write_file(self.response.out, records, get_notes_for_person) utils.log_api_action(self, ApiActionLog.SEARCH, len(records))
def get(self): if self.config.read_auth_key_required and not ( self.auth and self.auth.read_permission): self.info(403, message='Missing or invalid authorization key', style='plain') return pfif_version = self.params.version # Note that self.request.get can handle multiple IDs at once; we # can consider adding support for multiple records later. record_id = self.request.get('id') if not record_id: self.info(400, message='Missing id parameter', style='plain') return person = model.Person.get(self.repo, record_id, filter_expired=False) if not person: self.info(400, message='No person record with ID %s' % record_id, style='plain') return notes = model.Note.get_by_person_record_id(self.repo, record_id) notes = [note for note in notes if not note.hidden] self.response.headers['Content-Type'] = 'application/xml' records = [pfif_version.person_to_dict(person, person.is_expired)] note_records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) utils.optionally_filter_sensitive_fields(note_records, self.auth) pfif_version.write_file(self.response.out, records, lambda p: note_records) utils.log_api_action(self, ApiActionLog.READ, len(records), len(notes))
def get(self): if self.config.read_auth_key_required and not ( self.auth and self.auth.read_permission): self.response.set_status(403) self.write('Missing or invalid authorization key\n') return pfif_version = self.params.version # Note that self.request.get can handle multiple IDs at once; we # can consider adding support for multiple records later. record_id = self.request.get('id') if not record_id: return self.error(400, 'Missing id parameter') person = model.Person.get( self.repo, record_id, filter_expired=False) if not person: return self.error(404, 'No person record with ID %s' % record_id) notes = model.Note.get_by_person_record_id(self.repo, record_id) notes = [note for note in notes if not note.hidden] self.response.headers['Content-Type'] = 'application/xml' records = [pfif_version.person_to_dict(person, person.is_expired)] note_records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) utils.optionally_filter_sensitive_fields(note_records, self.auth) pfif_version.write_file( self.response.out, records, lambda p: note_records) utils.log_api_action( self, ApiActionLog.READ, len(records), len(notes))
def get(self): if self.config.search_auth_key_required and not ( self.auth and self.auth.search_permission): self.info( 403, message='Missing or invalid authorization key', style='plain') return pfif_version = self.params.version # Retrieve parameters and do some sanity checks on them. record_id = self.request.get('id') query_string = self.request.get('q') max_results = min(self.params.max_results or 100, HARD_MAX_RESULTS) results = [] if record_id: # Search by record ID (always returns just 1 result or nothing). person = model.Person.get(self.repo, record_id) if person: results = [person] elif query_string: # Search by query words. if self.config.external_search_backends: query = TextQuery(query_string) results = external_search.search(self.repo, query, max_results, self.config.external_search_backends) # External search backends are not always complete. Fall back to # the original search when they fail or return no results. if not results: if config.get('enable_fulltext_search'): results = full_text_search.search( self.repo, query_string, max_results) else: results = indexing.search( self.repo, TextQuery(query_string), max_results) else: self.info( 400, message='Neither id nor q parameter specified', style='plain') records = [pfif_version.person_to_dict(result) for result in results] utils.optionally_filter_sensitive_fields(records, self.auth) # Define the function to retrieve notes for a person. def get_notes_for_person(person): notes = model.Note.get_by_person_record_id( self.repo, person['person_record_id']) notes = [note for note in notes if not note.hidden] records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) return records self.response.headers['Content-Type'] = 'application/xml; charset=utf-8' pfif_version.write_file( self.response.out, records, get_notes_for_person) utils.log_api_action(self, ApiActionLog.SEARCH, len(records))
def get(self): repos = model.Repo.list_launched() if self.repo: repos = [self.repo] if self.repo in repos else [] self.response.headers['Content-Type'] = 'application/xml' atom.REPO_1_0.write_feed( self.response.out, repos, self.request.url, self.TITLE, get_latest_repo_updated_date(repos)) utils.log_api_action(self, model.ApiActionLog.REPO)
def get(self): repos = model.Repo.list_launched() if self.repo: repos = [self.repo] if self.repo in repos else [] self.response.headers['Content-Type'] = 'application/xml' atom.REPO_1_0.write_feed(self.response.out, repos, self.request.url, self.TITLE, get_latest_repo_updated_date(repos)) utils.log_api_action(self, model.ApiActionLog.REPO)
def get(self): if self.config.read_auth_key_required and not ( self.auth and self.auth.read_permission): self.response.set_status(403) self.write('Missing or invalid authorization key\n') return pfif_version = self.params.version atom_version = atom.ATOM_PFIF_VERSIONS.get(pfif_version.version) max_results = min(self.params.max_results or 10, HARD_MAX_RESULTS) skip = self.params.skip or 0 # We use a member because a var can't be modified inside the closure. self.num_notes = 0 def get_notes_for_person(person): notes = model.Note.get_by_person_record_id( self.repo, person['person_record_id']) # Show hidden notes as blank in the Person feed (melwitt) # https://web.archive.org/web/20111228161607/http://code.google.com/p/googlepersonfinder/issues/detail?id=58 make_hidden_notes_blank(notes) records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) self.num_notes += len(notes) return records if self.params.omit_notes: # Return only the person records. get_notes_for_person = lambda person: [] query = model.Person.all_in_repo(self.repo, filter_expired=False) if self.params.min_entry_date: # Scan forward. query = query.order('entry_date') query = query.filter('entry_date >=', self.params.min_entry_date) else: # Show recent entries, scanning backward. query = query.order('-entry_date') persons = query.fetch(max_results, offset=skip) updated = get_latest_entry_date(persons) self.response.headers[ 'Content-Type'] = 'application/xml; charset=utf-8' records = [ pfif_version.person_to_dict(person, person.is_expired) for person in persons ] utils.optionally_filter_sensitive_fields(records, self.auth) atom_version.write_person_feed(self.response.out, records, get_notes_for_person, self.request.url, self.env.netloc, PERSON_SUBTITLE_BASE + self.env.netloc, updated) utils.log_api_action(self, model.ApiActionLog.READ, len(records), self.num_notes)
def post(self): if not (self.auth and self.auth.subscribe_permission): return self.error(403, "Missing or invalid authorization key") subscription = model.Subscription.get(self.repo, self.params.id, self.params.subscribe_email) self.response.set_status(200) utils.log_api_action(self, ApiActionLog.UNSUBSCRIBE) if subscription: subscription.delete() return self.info(200, "Successfully unsubscribed") return self.info(200, "Not subscribed")
def post(self): if not (self.auth and self.auth.subscribe_permission): return self.error(403, 'Missing or invalid authorization key') subscription = model.Subscription.get(self.repo, self.params.id, self.params.subscribe_email) self.response.set_status(200) utils.log_api_action(self, ApiActionLog.UNSUBSCRIBE) if subscription: subscription.delete() return self.info(200, 'Successfully unsubscribed') return self.info(200, 'Not subscribed')
def post(self): if not (self.auth and self.auth.domain_write_permission): self.response.set_status(403) # TODO(ryok): i18n self.write('Missing or invalid authorization key.') return content = self.request.get('content') if not content: self.response.set_status(400) self.write('You need to specify at least one CSV file.') return # TODO(ryok): let the user select timezone. # TODO(ryok): accept more flexible date time format. # TODO(ryok): support non-UTF8 encodings. source_domain = self.auth.domain_write_permission records = importer.utf8_decoder( csv.DictReader(StringIO.StringIO(content))) try: records = [complete_record_ids(r, source_domain) for r in records] except csv.Error: self.response.set_status(400) self.write('The CSV file is formatted incorrectly.') return is_empty = lambda x: (x or '').strip() persons = [r for r in records if is_empty(r.get('full_name'))] notes = [r for r in records if is_empty(r.get('note_record_id'))] people_written, people_skipped, people_total = importer.import_records( self.repo, source_domain, importer.create_person, persons) notes_written, notes_skipped, notes_total = importer.import_records( self.repo, source_domain, importer.create_note, notes) utils.log_api_action(self, ApiActionLog.WRITE, people_written, notes_written, len(people_skipped), len(notes_skipped)) self.render('import.html', stats=[ Struct(type='Person', written=people_written, skipped=people_skipped, total=people_total), Struct(type='Note', written=notes_written, skipped=notes_skipped, total=notes_total)], **get_tag_params(self))
def get(self): if self.config.read_auth_key_required and not ( self.auth and self.auth.read_permission): self.response.set_status(403) self.write('Missing or invalid authorization key\n') return pfif_version = self.params.version atom_version = atom.ATOM_PFIF_VERSIONS.get(pfif_version.version) max_results = min(self.params.max_results or 10, HARD_MAX_RESULTS) skip = self.params.skip or 0 # We use a member because a var can't be modified inside the closure. self.num_notes = 0 def get_notes_for_person(person): notes = model.Note.get_by_person_record_id( self.repo, person['person_record_id']) # Show hidden notes as blank in the Person feed (melwitt) # http://code.google.com/p/googlepersonfinder/issues/detail?id=58 make_hidden_notes_blank(notes) records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) self.num_notes += len(notes) return records if self.params.omit_notes: # Return only the person records. get_notes_for_person = lambda person: [] query = model.Person.all_in_repo(self.repo, filter_expired=False) if self.params.min_entry_date: # Scan forward. query = query.order('entry_date') query = query.filter('entry_date >=', self.params.min_entry_date) else: # Show recent entries, scanning backward. query = query.order('-entry_date') persons = query.fetch(max_results, offset=skip) updated = get_latest_entry_date(persons) self.response.headers['Content-Type'] = 'application/xml' records = [pfif_version.person_to_dict(person, person.is_expired) for person in persons] utils.optionally_filter_sensitive_fields(records, self.auth) atom_version.write_person_feed( self.response.out, records, get_notes_for_person, self.request.url, self.env.netloc, PERSON_SUBTITLE_BASE + self.env.netloc, updated) utils.log_api_action(self, model.ApiActionLog.READ, len(records), self.num_notes)
def get(self): # SSL and auth key is not required if a feed for a specific person # is requested. Note that the feed icon on the person record page # links to HTTP version without auth key. if not self.params.person_record_id: # Check for SSL (unless running on localhost for development). if self.env.scheme != 'https' and self.env.domain != 'localhost': self.response.set_status(403) self.write('HTTPS is required.\n') return if self.config.read_auth_key_required and not ( self.auth and self.auth.read_permission): self.response.set_status(403) self.write('Missing or invalid authorization key\n') return pfif_version = self.params.version atom_version = atom.ATOM_PFIF_VERSIONS.get(pfif_version.version) max_results = min(self.params.max_results or 10, HARD_MAX_RESULTS) skip = self.params.skip or 0 query = model.Note.all_in_repo(self.repo) if self.params.min_entry_date: # Scan forward. query = query.order('entry_date') query = query.filter('entry_date >=', self.params.min_entry_date) else: # Show recent entries, scanning backward. query = query.order('-entry_date') if self.params.person_record_id: # Show notes for a specific person. query = query.filter('person_record_id =', self.params.person_record_id) notes = query.fetch(max_results, offset=skip) updated = get_latest_entry_date(notes) # Show hidden notes as blank in the Note feed (melwitt) # https://web.archive.org/web/20111228161607/http://code.google.com/p/googlepersonfinder/issues/detail?id=58 make_hidden_notes_blank(notes) self.response.headers[ 'Content-Type'] = 'application/xml; charset=utf-8' records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) atom_version.write_note_feed(self.response.out, records, self.request.url, self.env.netloc, NOTE_SUBTITLE_BASE + self.env.netloc, updated) utils.log_api_action(self, model.ApiActionLog.READ, 0, len(records))
def post(self): if not (self.auth and self.auth.subscribe_permission): return self.error(403, "Missing or invalid authorization key") if not subscribe.is_email_valid(self.params.subscribe_email): return self.error(400, "Invalid email address") person = model.Person.get(self.repo, self.params.id) if not person: return self.error(400, "Invalid person_record_id") subscription = subscribe.subscribe_to(self, self.repo, person, self.params.subscribe_email, self.env.lang) utils.log_api_action(self, ApiActionLog.SUBSCRIBE) if not subscription: return self.info(200, "Already subscribed") return self.info(200, "Successfully subscribed")
def get(self): # SSL and auth key is not required if a feed for a specific person # is requested. Note that the feed icon on the person record page # links to HTTP version without auth key. if not self.params.person_record_id: # Check for SSL (unless running on localhost for development). if self.env.scheme != 'https' and self.env.domain != 'localhost': self.response.set_status(403) self.write('HTTPS is required.\n') return if self.config.read_auth_key_required and not ( self.auth and self.auth.read_permission): self.response.set_status(403) self.write('Missing or invalid authorization key\n') return pfif_version = self.params.version atom_version = atom.ATOM_PFIF_VERSIONS.get(pfif_version.version) max_results = min(self.params.max_results or 10, HARD_MAX_RESULTS) skip = self.params.skip or 0 query = model.Note.all_in_repo(self.repo) if self.params.min_entry_date: # Scan forward. query = query.order('entry_date') query = query.filter('entry_date >=', self.params.min_entry_date) else: # Show recent entries, scanning backward. query = query.order('-entry_date') if self.params.person_record_id: # Show notes for a specific person. query = query.filter('person_record_id =', self.params.person_record_id) notes = query.fetch(max_results, offset=skip) updated = get_latest_entry_date(notes) # Show hidden notes as blank in the Note feed (melwitt) # http://code.google.com/p/googlepersonfinder/issues/detail?id=58 make_hidden_notes_blank(notes) self.response.headers['Content-Type'] = 'application/xml' records = map(pfif_version.note_to_dict, notes) utils.optionally_filter_sensitive_fields(records, self.auth) atom_version.write_note_feed( self.response.out, records, self.request.url, self.env.netloc, NOTE_SUBTITLE_BASE + self.env.netloc, updated) utils.log_api_action(self, model.ApiActionLog.READ, 0, len(records))
def post(self): if not (self.auth and self.auth.subscribe_permission): return self.error(403, 'Missing or invalid authorization key') if not subscribe.is_email_valid(self.params.subscribe_email): return self.error(400, 'Invalid email address') person = model.Person.get(self.repo, self.params.id) if not person: return self.error(400, 'Invalid person_record_id') subscription = subscribe.subscribe_to(self, self.repo, person, self.params.subscribe_email, self.env.lang) utils.log_api_action(self, ApiActionLog.SUBSCRIBE) if not subscription: return self.info(200, 'Already subscribed') return self.info(200, 'Successfully subscribed')
class Write(utils.BaseHandler): https_required = True def post(self): if not (self.auth and self.auth.domain_write_permission): self.info( 403, message='Missing or invalid authorization key', style='plain') return source_domain = self.auth.domain_write_permission try: person_records, note_records = \ pfif.parse_file(self.request.body_file) except Exception, e: self.info(400, message='Invalid XML: %s' % e, style='plain') return mark_notes_reviewed = bool(self.auth.mark_notes_reviewed) believed_dead_permission = bool( self.auth.believed_dead_permission) self.response.headers['Content-Type'] = 'application/xml; charset=utf-8' self.write('<?xml version="1.0"?>\n') self.write('<status:status ' + 'xmlns:status="http://zesty.ca/pfif/1.4/status" ' + 'xmlns:pfif="http://zesty.ca/pfif/1.4">\n') create_person = importer.create_person num_people_written, people_skipped, total = importer.import_records( self.repo, source_domain, create_person, person_records) self.write_status( 'person', num_people_written, people_skipped, total, 'person_record_id') create_note = importer.create_note num_notes_written, notes_skipped, total = importer.import_records( self.repo, source_domain, create_note, note_records, mark_notes_reviewed, believed_dead_permission, self) self.write_status( 'note', num_notes_written, notes_skipped, total, 'note_record_id') self.write('</status:status>\n') utils.log_api_action(self, ApiActionLog.WRITE, num_people_written, num_notes_written, len(people_skipped), len(notes_skipped))
source_domain = self.auth.domain_write_permission records = importer.utf8_decoder(generate_note_record_ids( convert_time_fields(csv.reader(lines)))) try: records = [complete_record_ids(r, source_domain) for r in records] except csv.Error, e: self.error(400, message= 'The CSV file is formatted incorrectly. (%s)' % e) return notes_written, notes_skipped, notes_total = importer.import_records( self.repo, source_domain, importer.create_note, records, believed_dead_permission=self.auth.believed_dead_permission, omit_duplicate_notes=True) utils.log_api_action(self, ApiActionLog.WRITE, 0, notes_written, 0, len(notes_skipped)) self.render('import.html', formats=get_requested_formats(self.env.path), stats=[ Struct(type='Note', written=notes_written, skipped=notes_skipped, total=notes_total)], **get_tag_params(self)) def import_persons(self, lines): # TODO(ryok): support non-UTF8 encodings. source_domain = self.auth.domain_write_permission records = importer.utf8_decoder(convert_time_fields(csv.reader(lines)))