setStatus function accepts extra_context as its parameter instead of url_names and linker.

The problem with the current apporach is that it is difficult to test it without specifying either Summer-of-Code or Code-in specific instance of UrlNames. At the same time, we would like to be able to test this function on Melange level, because this is the level on which the function is defined.

By passing URL, we actually delegate its creation to the outside code. Therefore, the code is more testable because we can pass in an arbitrary string.

It fixes two unit tests which were broken in revision 7f23a46198f8.
diff --git a/app/codein/views/helper/urls.py b/app/codein/views/helper/urls.py
index 47430c0..a868b14 100644
--- a/app/codein/views/helper/urls.py
+++ b/app/codein/views/helper/urls.py
@@ -27,3 +27,4 @@
   CONNECTION_PICK_ORG = 'connection_pick_org'
   CONNECTION_START_AS_ORG = 'connection_start_as_org'
   CONNECTION_START_AS_USER = 'connection_start_as_user'
+  ORG_PROFILE_EDIT = 'ci_org_profile_edit'
diff --git a/app/melange/logic/organization.py b/app/melange/logic/organization.py
index 105ae57..7cd8cae 100644
--- a/app/melange/logic/organization.py
+++ b/app/melange/logic/organization.py
@@ -35,8 +35,8 @@
 from soc.tasks import mailer
 
 
-DEF_LINKER_URL_NAMES_REQUIRED = translation.ugettext(
-    'Linker and UrlNames instances are required for accepting organizations.')
+EXTRA_CONTEXT_REQUIRED_ERROR = translation.ugettext(
+    'Extra context is required for accepting organizations.')
 
 ORG_ID_IN_USE = translation.ugettext(
     'Organization ID %s is already in use for this program.')
@@ -158,7 +158,7 @@
 
 @ndb.transactional
 def setStatus(organization, program, site, program_messages,
-              new_status, linker=None, url_names=None, org_admins=None):
+              new_status, org_admins=None, extra_context=None):
   """Sets status of the specified organization.
 
   This function may be called to accept the organization into the program
@@ -177,15 +177,13 @@
     program: Program entity to which organization is assigned.
     site: Site entity.
     program_messages: ProgramMessages entity that holds the message
-          templates provided by the program admins.
+      templates provided by the program admins.
     new_status: New status of the organization. Must be one of
       org_model.Status constants.
-    linker: Instance of links.Linker class (Optional: required only for
-      sending notifications).
-    url_names: Instance of url_names.UrlNames (Optional: required only for
-      sending notifications).
     org_admins: Optional list of organization administrators for the specified
       organization.
+    extra_context: Optional dict with additional context for notifications.
+      Right now, it is only required when status is set to accepted.
 
   Returns:
     The updated organization entity.
@@ -201,15 +199,13 @@
       recipients = [org_admin.contact.email for org_admin in org_admins]
 
       if new_status == org_model.Status.ACCEPTED:
-        if not (linker and url_names):
-          raise ValueError(DEF_LINKER_URL_NAMES_REQUIRED)
+        if not extra_context:
+          raise ValueError(EXTRA_CONTEXT_REQUIRED_ERROR)
 
         notification_context = (
-            notifications.OrganizationAcceptedContextProvider(linker,
-                                                              url_names)
-                .getContext(
-                    recipients, organization, program, site,
-                    program_messages))
+            notifications.OrganizationAcceptedContextProvider().getContext(
+                recipients, organization, program, site, program_messages,
+                extra_context))
 
         # organization administrators are also sent the welcome email
         for org_admin in org_admins:
diff --git a/app/melange/mapreduce/apply_org_admission_decisions.py b/app/melange/mapreduce/apply_org_admission_decisions.py
index 86d4038..3e0817c 100644
--- a/app/melange/mapreduce/apply_org_admission_decisions.py
+++ b/app/melange/mapreduce/apply_org_admission_decisions.py
@@ -52,9 +52,11 @@
   program_key = db.Key(context.mapreduce_spec.mapper.params['program_key'])
 
   if program_key.kind() == 'GSoCProgram':
-    url_names = soc_urls.UrlNames
+    url = links.ABSOLUTE_LINKER.organization(
+        org_key, soc_urls.UrlNames.ORG_PROFILE_EDIT)
   elif program_key.kind() == 'GCIProgram':
-    url_names = ci_urls.UrlNames
+    url = links.ABSOLUTE_LINKER.organization(
+        org_key, ci_urls.UrlNames.ORG_PROFILE_EDIT)
   else:
     raise ValueError('Invalid program type %s' % program_key.kind())
 
@@ -82,14 +84,14 @@
     organization = org_key.get()
     if organization.program.to_old_key() == program_key:
       if organization.status == org_model.Status.PRE_ACCEPTED:
+        extra_context = {'url': url}
         org_logic.setStatus(
             organization, program, site, program_messages,
-            org_model.Status.ACCEPTED, links.ABSOLUTE_LINKER, url_names,
-            org_admins=org_admins)
+            org_model.Status.ACCEPTED, org_admins=org_admins,
+            extra_context=extra_context)
       elif organization.status == org_model.Status.PRE_REJECTED:
         org_logic.setStatus(
             organization, program, site, program_messages,
-            org_model.Status.REJECTED, links.ABSOLUTE_LINKER, url_names,
-            org_admins=org_admins)
+            org_model.Status.REJECTED, org_admins=org_admins)
 
   updateOrganizationStatus()
diff --git a/app/soc/logic/helper/notifications.py b/app/soc/logic/helper/notifications.py
index 0d73660..ba4eb26 100644
--- a/app/soc/logic/helper/notifications.py
+++ b/app/soc/logic/helper/notifications.py
@@ -362,17 +362,9 @@
   is accepted into a program.
   """
 
-  def __init__(self, linker, url_names):
-    """Constructs the context provider for rejected org email notifications.
-
-    Args:
-      linker: Instance of links.Linker class.
-      url_names: Instance of url_names.UrlNames.
-    """
-    self.linker = linker
-    self.url_names = url_names
-
-  def getContext(self, emails, organization, program, site, program_messages):
+  def getContext(
+      self, emails, organization, program, site, program_messages,
+      extra_context):
     """Provides notification context of an email to send out when the specified
     organization is accepted into the program.
 
@@ -382,17 +374,16 @@
       program: Program entity.
       site: Site entity.
       program_messages: ProgramMessages entity that holds the message
-          templates provided by the program admins.
+        templates provided by the program admins.
+      extra_context: A dict containing additional context to be included in
+        the message.
     """
-    subject = DEF_ACCEPTED_ORG % {
-        'org': organization.name,
-        }
+    subject = DEF_ACCEPTED_ORG % {'org': organization.name, }
 
     message_properties = {
         'org': organization.name,
         'program_name': program.name,
-        'url': self.linker.organization(
-            organization.key, self.url_names.ORG_PROFILE_EDIT),
+        'url': extra_context['url']
     }
 
     return getContextFromTemplateString(
diff --git a/app/summerofcode/views/org_app.py b/app/summerofcode/views/org_app.py
index f0b03e7..c06a848 100644
--- a/app/summerofcode/views/org_app.py
+++ b/app/summerofcode/views/org_app.py
@@ -1131,8 +1131,9 @@
             message='Missing or invalid new status in POST data.')
       else:
         organization = org_key.get()
-        org_logic.setStatus(organization, data.program, data.site,
-                            data.program.getProgramMessages(), new_status)
+        org_logic.setStatus(
+            organization, data.program, data.site,
+            data.program.getProgramMessages(), new_status)
         return http.HttpResponse()
 
 
diff --git a/tests/app/melange/logic/test_organization.py b/tests/app/melange/logic/test_organization.py
index 185f410..8b9d299 100644
--- a/tests/app/melange/logic/test_organization.py
+++ b/tests/app/melange/logic/test_organization.py
@@ -329,9 +329,11 @@
 
   def testAcceptOrganization(self):
     """Tests that organization is successfully accepted."""
+    extra_context = {'url': 'http://unused.value.com'}
     org = org_logic.setStatus(
         self.org, self.program, self.site, self.program.getProgramMessages(),
-        org_model.Status.ACCEPTED, org_admins=[self.profile])
+        org_model.Status.ACCEPTED, org_admins=[self.profile],
+        extra_context=extra_context)
 
     self.assertEqual(org.status, org_model.Status.ACCEPTED)
     self.assertEmailSent(to=self.profile.contact.email)
@@ -347,9 +349,11 @@
       admins.append(profile_utils.seedNDBProfile(
           self.program.key(), admin_for=[self.org.key]))
 
+    extra_context = {'url': 'http://unused.value.com'}
     org_logic.setStatus(
         self.org, self.program, self.site, self.program.getProgramMessages(),
-        org_model.Status.ACCEPTED, org_admins=admins)
+        org_model.Status.ACCEPTED, org_admins=admins,
+        extra_context=extra_context)
 
     # check that acceptance / rejection email have been sent
     for admin in admins: