def get_email_for_inboxes(self, entry_ref, inboxes): subscribers_ref = self.get_actors_for_inboxes(inboxes) email_aliases = [] parent_entry_ref = api.entry_get_safe(api.ROOT, entry_ref.entry) owners = [entry_ref.owner, entry_ref.actor] if parent_entry_ref: owners.extend((parent_entry_ref.owner, parent_entry_ref.actor)) for subscriber_ref in subscribers_ref: # Only email if you are directly involved in the stream if subscriber_ref.nick not in owners: exists = api.subscription_exists( api.ROOT, entry_ref.entry, 'inbox/%s/overview' % subscriber_ref.nick) if not exists: continue if not subscriber_ref.extra.get('email_notify'): continue email = api.email_get_actor(api.ROOT, subscriber_ref.nick) if not email: continue actor_ref = api.actor_get(api.ROOT, entry_ref.actor) if subscriber_ref.nick == actor_ref.nick: continue email_aliases.append(email) return set(email_aliases)
def check_inboxes_for_entry(self, entry_ref, expected): inboxes = api.inbox_get_all_for_entry(api.ROOT, entry_ref.stream, entry_ref.uuid, entry_ref.entry) #self.assertEqual(len(inboxes), len(set(inboxes)), 'duplicates: %s' % inboxes) self.assertSetEqual(set(expected), set(inboxes)) for inbox in inboxes: actor_ref = api.actor_get(api.ROOT, util.get_user_from_topic(inbox)) if not api.entry_get_safe(actor_ref, entry_ref.keyname()): self.fail('An entry not visible by a user was added to their inbox') return inboxes
def check_inboxes_for_entry(self, entry_ref, expected): inboxes = api.inbox_get_all_for_entry(api.ROOT, entry_ref.stream, entry_ref.uuid, entry_ref.entry) #self.assertEqual(len(inboxes), len(set(inboxes)), 'duplicates: %s' % inboxes) self.assertSetEqual(set(expected), set(inboxes)) for inbox in inboxes: actor_ref = api.actor_get(api.ROOT, util.get_user_from_topic(inbox)) if not api.entry_get_safe(actor_ref, entry_ref.keyname()): self.fail( 'An entry not visible by a user was added to their inbox') return inboxes
def actor_item(request, nick=None, item=None, format='html'): # The nick passed in the url looks ugly with the escaped @ in it and is # generally just shorter if we only use the lead part of the nick # however the entire system expects full nicks so we should expand this # as soon as possible nick = clean.nick(nick) # Most pages have the concept of a viewer and an actor being viewed, # in all cases the viewer is `request.user` and the actor being viewed # should be named `view` view = api.actor_lookup_nick(request.user, nick) if not view: raise exception.UserDoesNotExistError(nick, request.user) # With very few exceptions, whenever we are referring to a an # instance that is an entity from the datastore we append `_ref` # to the variable name to distinguish it from the variable that # is simply a string identifier. # In the code below `stream_ref` and `entry_ref` are both entity # references, while `entry` is simply the string key_name of an entry stream_ref = api.stream_get_presence(request.user, view.nick) if not stream_ref: raise http.Http404() if item == 'last': entry_ref = api.entry_get_last(request.user, stream_ref.keyname()) return http.HttpResponseRedirect(entry_ref.url()) else: entry = '%s/%s' % (stream_ref.key().name(), item) entry_ref = api.entry_get_safe(request.user, entry) # Most api calls will return None if the entity being looked up does # not exist so we usually want to verify the return values if not entry_ref: raise http.Http404() # When handling user actions the following pattern more or less applies # if 'parameter_unique_to_action' in request.(POST|GET|REQUEST): # try: # validate.nonce(request, 'nonce_action') # validate.anything_else_that_is_related_to_ui_rather_than_call() # # local_variable = request.(POST|GET|REQUEST).get('request_arg') # # or # params = util.query_dict_to_keywords(request.(POST|GET|REQUEST)) # # # Our goal is to have most of the logic for any action translate # # directly into an api call on behalf of the requesting user # # such that the api call is responsible for validating all input # # and raising any applicable errors # result = api.some_api_method(request.user, # method_variable=local_variable, # ...) # # or # result = api.some_api_method(request.user, **params) # # # All actions should issue a redirect with a success message # return util.RedirectFlash('some_url', 'some success message') # except: # exception.handle_exception(request) # # When an exception occurs we expect the rest of the page to be able # to be processed normally as if no action had been taken, the error # handling section of the template should display the errors caught # by the exception.handle_exception() call handled = common_views.handle_view_action( request, {'entry_add_comment': entry_ref.url(request=request), 'entry_remove': view.url(request=request), 'entry_remove_comment': entry_ref.url(request=request), 'entry_mark_as_spam': entry_ref.url(request=request) } ) if handled: return handled comments = api.entry_get_comments(request.user, entry_ref.key().name()) # To minimize the number of lookups to the datastore once we know # all the data we will be displaying on a page we attempt to make # a list of all the actors associated with that data so that we can # fetch them all at once actor_nicks = [entry_ref.owner, entry_ref.actor] + [c.actor for c in comments] actors = api.actor_get_actors(request.user, actor_nicks) # Creates a copy of actors with lowercase keys (Django #6904: template filter # dictsort sorts case sensitive), excluding the currently logged in user. participants = {} for k, v in actors.iteritems(): if (v and not (hasattr(request.user, 'nick') and request.user.nick == v.nick)): participants[k.lower()] = v # Due to restrictions on Django's templating language most of the time # we will have to take an additional step of preparing all of our data # for display, this usually translates to attaching references to # actor or stream entities. # Functions that handle this preparation should be added to the # common.display module entry = display.prep_entry(entry_ref, {stream_ref.key().name(): stream_ref}, actors) comments = display.prep_comment_list(comments, actors) # Additionally, to minimize more logic in the templates some variables # can be defined to configure the output, these are usually template specific # though some are common variables for anything that inherits from the # base templates green_top = True sidebar_green_top = True # The quickest way to make sure we are getting all of the things we care # about passed to the template without the temptation of making last minute # changes is just to pass `locals()` to the template context c = template.RequestContext(request, locals()) # Ideally this is all that should be necessary to add additional output # formats, in practice it is yet to be seen whether additional data # preparation will be necessary before outputting in JSON or ATOM formats if format == 'html': # We always use the full path to the template to prevent naming conflicts # and difficult searches. t = loader.get_template('actor/templates/item.html') return http.HttpResponse(t.render(c)) elif format == 'json': t = loader.get_template('actor/templates/item.json') return util.HttpJsonResponse(t.render(c), request)
def actor_item(request, nick=None, item=None, format='html'): # The nick passed in the url looks ugly with the escaped @ in it and is # generally just shorter if we only use the lead part of the nick # however the entire system expects full nicks so we should expand this # as soon as possible nick = clean.nick(nick) # Most pages have the concept of a viewer and an actor being viewed, # in all cases the viewer is `request.user` and the actor being viewed # should be named `view` view = api.actor_lookup_nick(request.user, nick) if not view: raise exception.UserDoesNotExistError(nick, request.user) # With very few exceptions, whenever we are referring to a an # instance that is an entity from the datastore we append `_ref` # to the variable name to distinguish it from the variable that # is simply a string identifier. # In the code below `stream_ref` and `entry_ref` are both entity # references, while `entry` is simply the string key_name of an entry stream_ref = api.stream_get_presence(request.user, view.nick) if not stream_ref: raise http.Http404() if item == 'last': entry_ref = api.entry_get_last(request.user, stream_ref.keyname()) return http.HttpResponseRedirect(entry_ref.url()) else: entry = '%s/%s' % (stream_ref.key().name(), item) entry_ref = api.entry_get_safe(request.user, entry) # Most api calls will return None if the entity being looked up does # not exist so we usually want to verify the return values if not entry_ref: raise http.Http404() # When handling user actions the following pattern more or less applies # if 'parameter_unique_to_action' in request.(POST|GET|REQUEST): # try: # validate.nonce(request, 'nonce_action') # validate.anything_else_that_is_related_to_ui_rather_than_call() # # local_variable = request.(POST|GET|REQUEST).get('request_arg') # # or # params = util.query_dict_to_keywords(request.(POST|GET|REQUEST)) # # # Our goal is to have most of the logic for any action translate # # directly into an api call on behalf of the requesting user # # such that the api call is responsible for validating all input # # and raising any applicable errors # result = api.some_api_method(request.user, # method_variable=local_variable, # ...) # # or # result = api.some_api_method(request.user, **params) # # # All actions should issue a redirect with a success message # return util.RedirectFlash('some_url', 'some success message') # except: # exception.handle_exception(request) # # When an exception occurs we expect the rest of the page to be able # to be processed normally as if no action had been taken, the error # handling section of the template should display the errors caught # by the exception.handle_exception() call handled = common_views.handle_view_action( request, { 'entry_add_comment': entry_ref.url(request=request), 'entry_remove': view.url(request=request), 'entry_remove_comment': entry_ref.url(request=request), 'entry_mark_as_spam': entry_ref.url(request=request) }) if handled: return handled comments = api.entry_get_comments(request.user, entry_ref.key().name()) # To minimize the number of lookups to the datastore once we know # all the data we will be displaying on a page we attempt to make # a list of all the actors associated with that data so that we can # fetch them all at once actor_nicks = [entry_ref.owner, entry_ref.actor ] + [c.actor for c in comments] actors = api.actor_get_actors(request.user, actor_nicks) # Creates a copy of actors with lowercase keys (Django #6904: template filter # dictsort sorts case sensitive), excluding the currently logged in user. participants = {} for k, v in actors.iteritems(): if (v and not (hasattr(request.user, 'nick') and request.user.nick == v.nick)): participants[k.lower()] = v # Due to restrictions on Django's templating language most of the time # we will have to take an additional step of preparing all of our data # for display, this usually translates to attaching references to # actor or stream entities. # Functions that handle this preparation should be added to the # common.display module entry = display.prep_entry(entry_ref, {stream_ref.key().name(): stream_ref}, actors) comments = display.prep_comment_list(comments, actors) # Additionally, to minimize more logic in the templates some variables # can be defined to configure the output, these are usually template specific # though some are common variables for anything that inherits from the # base templates green_top = True sidebar_green_top = True # The quickest way to make sure we are getting all of the things we care # about passed to the template without the temptation of making last minute # changes is just to pass `locals()` to the template context c = template.RequestContext(request, locals()) # Ideally this is all that should be necessary to add additional output # formats, in practice it is yet to be seen whether additional data # preparation will be necessary before outputting in JSON or ATOM formats if format == 'html': # We always use the full path to the template to prevent naming conflicts # and difficult searches. t = loader.get_template('actor/templates/item.html') return http.HttpResponse(t.render(c)) elif format == 'json': t = loader.get_template('actor/templates/item.json') return util.HttpJsonResponse(t.render(c), request)