def post(self): if not self.params.text: return self.error( 200, _('Message is required. Please go back and try again.')) if not self.params.author_name: return self.error( 200, _('Your name is required in the "About you" section. ' 'Please go back and try again.')) if self.params.status == 'is_note_author' and not self.params.found: return self.error( 200, _('Please check that you have been in contact with ' 'the person after the earthquake, or change the ' '"Status of this person" field.')) note = Note.create_original( self.subdomain, entry_date=get_utcnow(), person_record_id=self.params.id, author_name=self.params.author_name, author_email=self.params.author_email, author_phone=self.params.author_phone, source_date=get_utcnow(), found=bool(self.params.found), status=self.params.status, email_of_found_person=self.params.email_of_found_person, phone_of_found_person=self.params.phone_of_found_person, last_known_location=self.params.last_known_location, text=self.params.text) entities_to_put = [note] # Update the Person based on the Note. person = Person.get(self.subdomain, self.params.id) if person: person.update_from_note(note) # Send notification to all people # who subscribed to updates on this person subscribe.send_notifications(person, note, self) entities_to_put.append(person) # Write one or both entities to the store. db.put(entities_to_put) # If user wants to subscribe to updates, redirect to the subscribe page if self.params.subscribe: return self.redirect('/subscribe', id=person.record_id, subscribe_email=self.params.author_email) # Redirect to this page so the browser's back button works properly. self.redirect('/view', id=self.params.id, query=self.params.query)
def send_notifications(handler, persons, notes): """For each note, send a notification to subscriber. Args: notes: List of notes for which to send notification. persons: Dictionary of persons impacted by the notes, indexed by person_record_id. handler: Handler used to send email notification. """ for note in notes: person = persons[note.person_record_id] subscribe.send_notifications(handler, person, [note])
def post(self): if not self.params.text: return self.error( 200, _('Message is required. Please go back and try again.')) if not self.params.author_name: return self.error( 200, _('Your name is required in the "About you" section. Please go back and try again.' )) # TODO: To reduce possible abuse, we currently limit to 3 person # match. We could guard using e.g. an XSRF token, which I don't know how # to build in GAE. ids = set() for i in [1, 2, 3]: id = getattr(self.params, 'id%d' % i) if not id: break ids.add(id) if len(ids) > 1: notes = [] for person_id in ids: person = Person.get(self.repo, person_id) person_notes = [] for other_id in ids - set([person_id]): note = Note.create_original( self.repo, entry_date=get_utcnow(), person_record_id=person_id, linked_person_record_id=other_id, text=self.params.text, author_name=self.params.author_name, author_phone=self.params.author_phone, author_email=self.params.author_email, source_date=get_utcnow()) person_notes.append(note) # Notify person's subscribers of all new duplicates. We do not # follow links since each Person record in the ids list gets its # own note. However, 1) when > 2 records are marked as # duplicates, subscribers will still receive multiple # notifications, and 2) subscribers to already-linked Persons # will not be notified of the new link. subscribe.send_notifications(self, person, person_notes, False) notes += person_notes # Write all notes to store db.put(notes) self.redirect('/view', id=self.params.id1)
def post(self): if not self.params.text: return self.error( 200, _('Message is required. Please go back and try again.')) if not self.params.author_name: return self.error( 200, _('Your name is required in the "About you" section. Please go back and try again.')) # TODO: To reduce possible abuse, we currently limit to 3 person # match. We could guard using e.g. an XSRF token, which I don't know how # to build in GAE. ids = set() for i in [1, 2, 3]: id = getattr(self.params, 'id%d' % i) if not id: break ids.add(id) if len(ids) > 1: notes = [] for person_id in ids: person = Person.get(self.repo, person_id) person_notes = [] for other_id in ids - set([person_id]): note = Note.create_original( self.repo, entry_date=get_utcnow(), person_record_id=person_id, linked_person_record_id=other_id, text=self.params.text, author_name=self.params.author_name, author_phone=self.params.author_phone, author_email=self.params.author_email, source_date=get_utcnow()) person_notes.append(note) # Notify person's subscribers of all new duplicates. We do not # follow links since each Person record in the ids list gets its # own note. However, 1) when > 2 records are marked as # duplicates, subscribers will still receive multiple # notifications, and 2) subscribers to already-linked Persons # will not be notified of the new link. subscribe.send_notifications(self, person, person_notes, False) notes += person_notes # Write all notes to store db.put(notes) self.redirect('/view', id=self.params.id1)
def confirm_note_with_bad_words(self, note): """After a note containing bad words is confirmed by the author, we will: (1) set note.confirmed = True; (2) copy the note from NoteWithBadWords to Note; (3) log user action; (4) update person record. """ note.confirmed = True; # Check whether the record author disabled notes on # this record during the time between the note author inputs the # note in the UI and confirms the note through email. person = model.Person.get(self.repo, note.person_record_id) if person.notes_disabled: return self.error( 200, _('The author has disabled notes on this record.')) # Check whether the admin disabled reporting "believed_dead" # during the time between the note author inputs the # note in the UI and confirms the note through email. if (self.params.status == 'believed_dead' and not self.config.allow_believed_dead_via_ui): return self.error( 200, _('Not authorized to post notes with the status ' '"believed_dead".')) # clone the flagged note to Note table. note_confirmed = model.Note.create_original( self.repo, entry_date=note.entry_date, person_record_id=note.person_record_id, author_name=note.author_name, author_email=note.author_email, author_phone=note.author_phone, source_date=note.source_date, author_made_contact=note.author_made_contact, status=note.status, email_of_found_person=note.email_of_found_person, phone_of_found_person=note.phone_of_found_person, last_known_location=note.last_known_location, text=note.text) entities_to_put = [note_confirmed] note.confirmed_copy_id = note_confirmed.get_record_id() entities_to_put.append(note) # Specially log 'believed_dead'. if note_confirmed.status == 'believed_dead': model.UserActionLog.put_new( 'mark_dead', note_confirmed, person.primary_full_name, self.request.remote_addr) # Specially log a switch to an alive status. if (note_confirmed.status in ['believed_alive', 'is_note_author'] and person.latest_status not in ['believed_alive', 'is_note_author']): model.UserActionLog.put_new( 'mark_alive', note_confirmed, person.primary_full_name) # Update the Person based on the Note. if person: person.update_from_note(note_confirmed) # Send notification to all people # who subscribed to updates on this person subscribe.send_notifications(self, person, [note_confirmed]) entities_to_put.append(person) # Write one or both entities to the store. db.put(entities_to_put)
class Handler(BaseHandler): def get(self): # Check the request parameters. if not self.params.id: return self.error(404, _('No person id was specified.')) try: person = Person.get(self.repo, self.params.id) # TODO(ichikawa) Consider removing this "except" clause. # I don't think ValueError is thrown here. except ValueError: return self.error( 404, _("This person's entry does not exist or has been deleted.")) if not person: return self.error( 404, _("This person's entry does not exist or has been deleted.")) # Render the page. self.render('add_note.html', person=person) def post(self): """Post a note in person's record view page""" try: create.validate_note_data( config=self.config, status=self.params.status, author_name=self.params.author_name, author_email=self.params.author_email, author_made_contact=self.params.author_made_contact, text=self.params.text) except create.CreationError as e: return self.error(400, e.user_readable_message) person = Person.get(self.repo, self.params.id) if person.notes_disabled: return self.error( 400, _('The author has disabled status updates ' 'on this record.')) # If a photo was uploaded, create and store a new Photo entry and get # the URL where it's served; otherwise, use the note_photo_url provided. photo, photo_url = (None, self.params.note_photo_url) if self.params.note_photo is not None: try: photo, photo_url = create_photo(self.params.note_photo, self.repo, self.transitionary_get_url) except PhotoError, e: return self.error(400, e.message) photo.put() try: note = create.create_note( repo=self.repo, person=person, config=self.config, user_ip_address=self.request.remote_addr, status=self.params.status, source_date=get_utcnow(), author_name=self.params.author_name, author_email=self.params.author_email, author_phone=self.params.author_phone, author_made_contact=bool(self.params.author_made_contact), note_photo=photo, note_photo_url=photo_url, text=self.params.text, email_of_found_person=self.params.email_of_found_person, phone_of_found_person=self.params.phone_of_found_person, last_known_location=self.params.last_known_location, validate_data=False) except create.FlaggedNoteException as e: return self.redirect('/post_flagged_note', id=e.note.get_record_id(), author_email=e.note.author_email, repo=self.repo) # Update the Person based on the Note. if person: person.update_from_note(note) # Send notification to all people # who subscribed to updates on this person subscribe.send_notifications(self, person, [note]) # write the updated person record to datastore db.put(person) # If user wants to subscribe to updates, redirect to the subscribe page if self.params.subscribe: return self.redirect('/subscribe', id=person.record_id, subscribe_email=self.params.author_email, context='add_note') # Redirect to view page so the browser's back button works properly. self.redirect('/view', id=self.params.id, query=self.params.query)
class Handler(BaseHandler): def get(self): # Check the request parameters. if not self.params.id: return self.error(404, _('No person id was specified.')) try: person = Person.get(self.repo, self.params.id) # TODO(ichikawa) Consider removing this "except" clause. # I don't think ValueError is thrown here. except ValueError: return self.error(404, _("This person's entry does not exist or has been deleted.")) if not person: return self.error(404, _("This person's entry does not exist or has been deleted.")) # Render the page. enable_notes_url = self.get_url('/enable_notes', id=self.params.id) self.render('add_note.html', person=person, enable_notes_url=enable_notes_url) def post(self): """Post a note in person's record view page""" if not self.params.text: return self.error( 400, _('Message is required. Please go back and try again.')) if not self.params.author_name: return self.error( 400, _('Your name is required in the "About you" section. ' 'Please go back and try again.')) if (self.params.status == 'is_note_author' and not self.params.author_made_contact): return self.error( 400, _('Please check that you have been in contact with ' 'the person after the disaster, or change the ' '"Status of this person" field.')) if (self.params.status == 'believed_dead' and not self.config.allow_believed_dead_via_ui): return self.error( 400, _('Not authorized to post notes with the status ' '"believed_dead".')) if (self.params.author_email and not utils.validate_email(self.params.author_email)): return self.error(400, _( 'The email address you entered appears to be invalid.')) person = Person.get(self.repo, self.params.id) if person.notes_disabled: return self.error( 400, _('The author has disabled status updates ' 'on this record.')) # If a photo was uploaded, create and store a new Photo entry and get # the URL where it's served; otherwise, use the note_photo_url provided. photo, photo_url = (None, self.params.note_photo_url) if self.params.note_photo is not None: try: photo, photo_url = create_photo( self.params.note_photo, self.repo, self.transitionary_get_url) except PhotoError, e: return self.error(400, e.message) photo.put() spam_detector = SpamDetector(self.config.bad_words) spam_score = spam_detector.estimate_spam_score(self.params.text) if (spam_score > 0): note = NoteWithBadWords.create_original( self.repo, entry_date=get_utcnow(), person_record_id=self.params.id, author_name=self.params.author_name, author_email=self.params.author_email, author_phone=self.params.author_phone, source_date=get_utcnow(), author_made_contact=bool(self.params.author_made_contact), status=self.params.status, email_of_found_person=self.params.email_of_found_person, phone_of_found_person=self.params.phone_of_found_person, last_known_location=self.params.last_known_location, text=self.params.text, photo=photo, photo_url=photo_url, spam_score=spam_score, confirmed=False) # Write the new NoteWithBadWords to the datastore note.put_new() # When the note is detected as spam, we do not update person record # or log action. We ask the note author for confirmation first. return self.redirect('/post_flagged_note', id=note.get_record_id(), author_email=note.author_email, repo=self.repo) else: note = Note.create_original( self.repo, entry_date=get_utcnow(), person_record_id=self.params.id, author_name=self.params.author_name, author_email=self.params.author_email, author_phone=self.params.author_phone, source_date=get_utcnow(), author_made_contact=bool(self.params.author_made_contact), status=self.params.status, email_of_found_person=self.params.email_of_found_person, phone_of_found_person=self.params.phone_of_found_person, last_known_location=self.params.last_known_location, text=self.params.text, photo=photo, photo_url=photo_url) # Write the new regular Note to the datastore note.put_new() # Specially log 'believed_dead'. if note.status == 'believed_dead': UserActionLog.put_new( 'mark_dead', note, person.primary_full_name, self.request.remote_addr) # Specially log a switch to an alive status. if (note.status in ['believed_alive', 'is_note_author'] and person.latest_status not in ['believed_alive', 'is_note_author']): UserActionLog.put_new('mark_alive', note, person.primary_full_name) # Update the Person based on the Note. if person: person.update_from_note(note) # Send notification to all people # who subscribed to updates on this person subscribe.send_notifications(self, person, [note]) # write the updated person record to datastore db.put(person) # If user wants to subscribe to updates, redirect to the subscribe page if self.params.subscribe: return self.redirect('/subscribe', id=person.record_id, subscribe_email=self.params.author_email, context='add_note') # Redirect to view page so the browser's back button works properly. self.redirect('/view', id=self.params.id, query=self.params.query)
def confirm_note_with_bad_words(self, note): """After a note containing bad words is confirmed by the author, we will: (1) set note.confirmed = True; (2) copy the note from NoteWithBadWords to Note; (3) log user action; (4) update person record. """ note.confirmed = True # Check whether the record author disabled notes on # this record during the time between the note author inputs the # note in the UI and confirms the note through email. person = model.Person.get(self.repo, note.person_record_id) if person.notes_disabled: return self.error( 200, _('The author has disabled notes on this record.')) # Check whether the admin disabled reporting "believed_dead" # during the time between the note author inputs the # note in the UI and confirms the note through email. if (self.params.status == 'believed_dead' and not self.config.allow_believed_dead_via_ui): return self.error( 200, _('Not authorized to post notes with the status ' '"believed_dead".')) # clone the flagged note to Note table. note_confirmed = model.Note.create_original( self.repo, entry_date=note.entry_date, person_record_id=note.person_record_id, author_name=note.author_name, author_email=note.author_email, author_phone=note.author_phone, source_date=note.source_date, author_made_contact=note.author_made_contact, status=note.status, email_of_found_person=note.email_of_found_person, phone_of_found_person=note.phone_of_found_person, last_known_location=note.last_known_location, text=note.text) entities_to_put = [note_confirmed] note.confirmed_copy_id = note_confirmed.get_record_id() entities_to_put.append(note) # Specially log 'believed_dead'. if note_confirmed.status == 'believed_dead': model.UserActionLog.put_new('mark_dead', note_confirmed, person.primary_full_name, self.request.remote_addr) # Specially log a switch to an alive status. if (note_confirmed.status in ['believed_alive', 'is_note_author'] and person.latest_status not in ['believed_alive', 'is_note_author']): model.UserActionLog.put_new('mark_alive', note_confirmed, person.primary_full_name) # Update the Person based on the Note. if person: person.update_from_note(note_confirmed) # Send notification to all people # who subscribed to updates on this person subscribe.send_notifications(self, person, [note_confirmed]) entities_to_put.append(person) # Write one or both entities to the store. db.put(entities_to_put)
class Handler(BaseHandler): def get(self): # Check the request parameters. if not self.params.id: return self.error(404, 'No person id was specified.') try: person = Person.get(self.repo, self.params.id) except ValueError: return self.error( 404, _("This person's entry does not exist or has been deleted.")) if not person: return self.error( 404, _("This person's entry does not exist or has been deleted.")) standalone = self.request.get('standalone') # Check if private info should be revealed. content_id = 'view:' + self.params.id reveal_url = reveal.make_reveal_url(self, content_id) show_private_info = reveal.verify(content_id, self.params.signature) # Compute the local times for the date fields on the person. person.source_date_local_string = self.to_formatted_local_time( person.source_date) person.expiry_date_local_string = self.to_formatted_local_time( person.get_effective_expiry_date()) # Get the notes and duplicate links. try: notes = person.get_notes() except datastore_errors.NeedIndexError: notes = [] person.sex_text = get_person_sex_text(person) for note in notes: self.add_fields_to_notes(note) try: linked_persons = person.get_all_linked_persons() except datastore_errors.NeedIndexError: linked_persons = [] linked_person_info = [] for linked_person in linked_persons: try: linked_notes = linked_person.get_notes() except datastore_errors.NeedIndexError: linked_notes = [] for note in linked_notes: self.add_fields_to_notes(note) linked_person_info.append( dict(id=linked_person.record_id, name=linked_person.primary_full_name, view_url=self.get_url('/view', id=linked_person.record_id), notes=linked_notes)) # Render the page. dupe_notes_url = self.get_url('/view', id=self.params.id, dupe_notes='yes') results_url = self.get_url('/results', role=self.params.role, query=self.params.query, given_name=self.params.given_name, family_name=self.params.family_name) feed_url = self.get_url('/feeds/note', person_record_id=self.params.id, repo=self.repo) subscribe_url = self.get_url('/subscribe', id=self.params.id) delete_url = self.get_url('/delete', id=self.params.id) disable_notes_url = self.get_url('/disable_notes', id=self.params.id) enable_notes_url = self.get_url('/enable_notes', id=self.params.id) extend_url = None extension_days = 0 expiration_days = None expiry_date = person.get_effective_expiry_date() if expiry_date and not person.is_clone(): expiration_delta = expiry_date - get_utcnow() extend_url = self.get_url('/extend', id=self.params.id) extension_days = extend.get_extension_days(self) if expiration_delta.days < EXPIRY_WARNING_THRESHOLD: # round 0 up to 1, to make the msg read better. expiration_days = expiration_delta.days + 1 if person.is_clone(): person.provider_name = person.get_original_domain() sanitize_urls(person) for note in notes: sanitize_urls(note) if person.profile_urls: person.profile_pages = get_profile_pages(person.profile_urls, self) self.render('view.html', person=person, notes=notes, linked_person_info=linked_person_info, standalone=standalone, onload_function='view_page_loaded()', show_private_info=show_private_info, admin=users.is_current_user_admin(), dupe_notes_url=dupe_notes_url, results_url=results_url, reveal_url=reveal_url, feed_url=feed_url, subscribe_url=subscribe_url, delete_url=delete_url, disable_notes_url=disable_notes_url, enable_notes_url=enable_notes_url, extend_url=extend_url, extension_days=extension_days, expiration_days=expiration_days) def post(self): if not self.params.text: return self.error( 200, _('Message is required. Please go back and try again.')) if not self.params.author_name: return self.error( 200, _('Your name is required in the "About you" section. ' 'Please go back and try again.')) if (self.params.status == 'is_note_author' and not self.params.author_made_contact): return self.error( 200, _('Please check that you have been in contact with ' 'the person after the earthquake, or change the ' '"Status of this person" field.')) if (self.params.status == 'believed_dead' and not self.config.allow_believed_dead_via_ui): return self.error( 200, _('Not authorized to post notes with the status ' '"believed_dead".')) person = Person.get(self.repo, self.params.id) if person.notes_disabled: return self.error( 200, _('The author has disabled status updates ' 'on this record.')) # If a photo was uploaded, create and store a new Photo entry and get # the URL where it's served; otherwise, use the note_photo_url provided. photo, photo_url = (None, self.params.note_photo_url) if self.params.note_photo is not None: try: photo, photo_url = create_photo(self.params.note_photo, self) except PhotoError, e: return self.error(400, e.message) photo.put() spam_detector = SpamDetector(self.config.bad_words) spam_score = spam_detector.estimate_spam_score(self.params.text) if (spam_score > 0): note = NoteWithBadWords.create_original( self.repo, entry_date=get_utcnow(), person_record_id=self.params.id, author_name=self.params.author_name, author_email=self.params.author_email, author_phone=self.params.author_phone, source_date=get_utcnow(), author_made_contact=bool(self.params.author_made_contact), status=self.params.status, email_of_found_person=self.params.email_of_found_person, phone_of_found_person=self.params.phone_of_found_person, last_known_location=self.params.last_known_location, text=self.params.text, photo=photo, photo_url=photo_url, spam_score=spam_score, confirmed=False) # Write the new NoteWithBadWords to the datastore db.put(note) UserActionLog.put_new('add', note, copy_properties=False) # When the note is detected as spam, we do not update person record # or log action. We ask the note author for confirmation first. return self.redirect('/post_flagged_note', id=note.get_record_id(), author_email=note.author_email, repo=self.repo) else: note = Note.create_original( self.repo, entry_date=get_utcnow(), person_record_id=self.params.id, author_name=self.params.author_name, author_email=self.params.author_email, author_phone=self.params.author_phone, source_date=get_utcnow(), author_made_contact=bool(self.params.author_made_contact), status=self.params.status, email_of_found_person=self.params.email_of_found_person, phone_of_found_person=self.params.phone_of_found_person, last_known_location=self.params.last_known_location, text=self.params.text, photo=photo, photo_url=photo_url) # Write the new regular Note to the datastore db.put(note) UserActionLog.put_new('add', note, copy_properties=False) # Specially log 'believed_dead'. if note.status == 'believed_dead': UserActionLog.put_new('mark_dead', note, person.primary_full_name, self.request.remote_addr) # Specially log a switch to an alive status. if (note.status in ['believed_alive', 'is_note_author'] and person.latest_status not in ['believed_alive', 'is_note_author']): UserActionLog.put_new('mark_alive', note, person.primary_full_name) # Update the Person based on the Note. if person: person.update_from_note(note) # Send notification to all people # who subscribed to updates on this person subscribe.send_notifications(self, person, [note]) # write the updated person record to datastore db.put(person) # If user wants to subscribe to updates, redirect to the subscribe page if self.params.subscribe: return self.redirect('/subscribe', id=person.record_id, subscribe_email=self.params.author_email, context='add_note') # Redirect to this page so the browser's back button works properly. self.redirect('/view', id=self.params.id, query=self.params.query)