Example #1
0
def post_document(request, pk):
    document = get_object_or_404(Document, pk=pk)
    signature = Signature(document=document)
    signature.data = {
        f.get_name(): request.POST.get(f.get_name(), None)
        for f in document.documentfield_set.all()
    }
    if request.user.is_authenticated():
        signature.user = request.user
    signature.save()
    if document.pk == 5:  #! TODO this will probably need to be abstracted at some point
        a = API("txrxlabs.freshdesk.com",
                settings.FRESHDESK_API_KEY,
                version=2)
        error = None
        try:
            send_template_email("email/work_request",
                                ['*****@*****.**'],
                                context={
                                    'signature': signature,
                                    "error": error
                                })
            a.tickets.create_ticket(
                'New work request for %s' % signature.data['name'],
                email=signature.data['email'],
                description=render_template("email/work_request",
                                            {'signature': signature})[0],
                tags=['work'])
        except Exception, e:
            error = e
        send_template_email("email/work_request", ['*****@*****.**'],
                            context={
                                'signature': signature,
                                "error": error
                            })
Example #2
0
 def send_payment_confirmation_email(cls,order,order_items):
   context = {
     'sessions': [i.product.session for i in order_items],
     'order_items': order_items,
     'new_user': (datetime.datetime.now() - order.user.date_joined) < datetime.timedelta(1),
     'SITE_NAME': settings.SITE_NAME,
   }
   send_template_email("email/course_enrollment",[order.user.email],context=context)
Example #3
0
 def send_payment_confirmation_email(cls, order, order_items):
     context = {
         'sessions': [i.product.session for i in order_items],
         'order_items':
         order_items,
         'new_user': (datetime.datetime.now() - order.user.date_joined) <
         datetime.timedelta(1),
         'SITE_NAME':
         settings.SITE_NAME,
     }
     send_template_email("email/course_enrollment", [order.user.email],
                         context=context)
Example #4
0
 def handle(self, *args, **options):
     tomorrow = arrow.utcnow().replace(hour=6, days=1).datetime
     next_day = arrow.utcnow().replace(hour=6, days=2).datetime
     class_times = ClassTime.objects.filter(start__gte=tomorrow,
                                            start__lte=next_day,
                                            emailed__isnull=True)
     class_times = class_times.exclude(
         session__course__active=False).exclude(
             session__active=False).distinct()
     if not class_times:
         return
     print "showing classes from %s to %s" % (tomorrow, next_day)
     print "reminding %s class times" % len(class_times)
     instructor_count = 0
     student_count = 0
     sent = []
     for class_time in class_times:
         instructor_count += 1
         instructor = class_time.session.user
         _dict = {
             'user': instructor,
             'la_key': LimitedAccessKey.new(instructor),
             'SITE_URL': settings.SITE_URL,
             'session': class_time.session,
             'class_time': class_time,
         }
         send_template_email("email/teaching_reminder",
                             instructor.email,
                             context=_dict,
                             experimental=False)
         for enrollment in class_time.session.enrollment_set.all():
             student_count += 1
             user = enrollment.user
             _dict = {
                 'user': user,
                 'la_key': LimitedAccessKey.new(user),
                 'SITE_URL': settings.SITE_URL,
                 'session': class_time.session,
                 'class_time': class_time,
             }
             if user.email in sent:
                 continue
             sent.append(user.email)
             send_template_email("email/course_reminder",
                                 user.email,
                                 context=_dict,
                                 experimental=False)
         class_time.emailed = arrow.utcnow().datetime
         class_time.save()
     print "\n\n\nemailed %s instructors and %s students" % (
         instructor_count, student_count)
Example #5
0
def master(request, app_name, model_name):
    model = apps.get_app_config(app_name).get_model(model_name)
    objs = model.objects.user_controls(request.user)

    if request.GET.get('user_search', ''):
        user_ids = get_user_model().objects.keyword_search(
            request.GET['user_search'], fields="*")
        objs = objs.filter(user_id__in=user_ids)
    elif request.GET.get("object_id", "").isdigit():
        objs = objs.filter(object_id=request.GET['object_id'])
    objs = objs.distinct()

    if request.POST:
        try:
            obj = objs.get(pk=request.POST['object_id'])
        except model.DoesNotExist:
            raise NotImplementedError(
                "%s cannot edit %s with id #%s" %
                (request.user, model, request.POST['pk']))
        action = request.POST.get('action', None).lower() or "new"
        obj.change_status(action)
        obj.save()
        if action == "completed" and model_name == "rsvp":
            send_template_email("email/completed_rsvp",
                                obj.user.email,
                                context={"rsvp": obj})
        out = obj.as_json
        out['message'] = '%s marked as "%s".' % (obj, action)
        return JsonResponse(out)
    cutoff = None
    if objs.count() > 20 and not request.GET.get('nocutoff', None):
        cutoff = datetime.datetime.now() - datetime.timedelta(60)
        objs = objs.filter(datetime__gte=cutoff)
    events = {}
    for obj in objs:
        if not obj.content_object in events:
            events[obj.content_object] = []
        events[obj.content_object].append(obj.as_json)
    events = [{
        'name': event.name,
        'start': event.start if hasattr(event, 'start') else "",
        'end': event.end if hasattr(event, 'start') else '',
        'objects': objects,
    } for event, objects in events.items()]
    values = {
        'events': json.dumps(events, cls=DjangoJSONEncoder),
        'model_slug': "%s.%s" % (app_name, model_name),
        'cutoff': cutoff,
        'model_name': model._meta.verbose_name
    }
    return TemplateResponse(request, 'tool/master.html', values)
Example #6
0
def container(request,pk):
  container = get_object_or_404(Container,pk=pk)
  action = request.GET['action']
  if action == "send_mail":
    container.status = "emailed"
    container.save()
    values = {'container': container}
    send_template_email("email/canceled_container",container.subscription.user.email,
                        from_email="*****@*****.**",context=values)
    messages.success(request,"%s has been marked as emailed."%(container))
  if action in ["emailed", "open","maintenance"]:
    container.status = action
    container.save()
    messages.success(request,"%s has been marked as %s."%(container,action))
  return HttpResponseRedirect("/admin/membership/container/%s"%container.pk)
Example #7
0
def container(request,pk):
  container = get_object_or_404(Container,pk=pk)
  action = request.GET['action']
  if action == "send_mail":
    container.status = "emailed"
    container.save()
    values = {'container': container}
    send_template_email("email/canceled_container",container.subscription.user.email,
                        from_email="*****@*****.**",context=values)
    messages.success(request,"%s has been marked as emailed."%(container))
  if action in ["emailed", "open","maintenance"]:
    container.status = action
    container.save()
    messages.success(request,"%s has been marked as %s."%(container,action))
  return HttpResponseRedirect("/admin/membership/container/%s"%container.pk)
Example #8
0
def master(request,app_name,model_name):
  model = apps.get_app_config(app_name).get_model(model_name)
  objs = model.objects.user_controls(request.user)

  if request.GET.get('user_search',''):
    user_ids = get_user_model().objects.keyword_search(request.GET['user_search'],fields="*")
    objs = objs.filter(user_id__in=user_ids)
  elif request.GET.get("object_id","").isdigit():
    objs = objs.filter(object_id=request.GET['object_id'])
  objs = objs.distinct()

  if request.POST:
    try:
      obj = objs.get(pk=request.POST['object_id'])
    except model.DoesNotExist:
      raise NotImplementedError("%s cannot edit %s with id #%s"%(request.user,model,request.POST['pk']))
    action = request.POST.get('action',None).lower() or "new"
    obj.change_status(action)
    obj.save()
    if action == "completed" and model_name == "rsvp":
      send_template_email("email/completed_rsvp",obj.user.email,context={ "rsvp": obj })
    out = obj.as_json
    out['message'] = '%s marked as "%s".'%(obj,action)
    return JsonResponse(out)
  cutoff = None
  if objs.count() > 20 and not request.GET.get('nocutoff',None):
    cutoff = datetime.datetime.now()-datetime.timedelta(60)
    objs = objs.filter(datetime__gte=cutoff)
  events = {}
  for obj in objs:
    if not obj.content_object in events:
      events[obj.content_object] = []
    events[obj.content_object].append(obj.as_json)
  events = [{
    'name': event.name,
    'start': event.start if hasattr(event,'start') else "",
    'end': event.end if hasattr(event,'start') else '',
    'objects': objects,
  } for event,objects in events.items()]
  values = {
    'events': json.dumps(events,cls=DjangoJSONEncoder),
    'model_slug': "%s.%s"%(app_name,model_name),
    'cutoff': cutoff,
    'model_name': model._meta.verbose_name
  }
  return TemplateResponse(request,'tool/master.html',values)
Example #9
0
def post_document(request,pk):
  document = get_object_or_404(Document,pk=pk)
  signature = Signature(document=document)
  signature.data = { f.get_name(): request.POST.get(f.get_name(),None) for f in document.documentfield_set.all() }
  if request.user.is_authenticated():
    signature.user = request.user
  signature.save()
  if document.pk == 5: #! TODO this will probably need to be abstracted at some point
    a = API("txrxlabs.freshdesk.com",settings.FRESHDESK_API_KEY,version=2)
    error = None
    try:
      send_template_email("email/work_request",['*****@*****.**'],context={'signature':signature,"error":error})
      a.tickets.create_ticket('New work request for %s'%signature.data['name'],
                              email=signature.data['email'],
                              description=render_template("email/work_request",{'signature':signature})[0],
                              tags=['work'])
    except Exception,e:
      error = e
    send_template_email("email/work_request",['*****@*****.**'],context={'signature':signature,"error":error})
Example #10
0
 def handle(self, *args, **options):
   tomorrow = arrow.utcnow().replace(hour=6,days=1).datetime
   next_day = arrow.utcnow().replace(hour=6,days=2).datetime
   class_times = ClassTime.objects.filter(start__gte=tomorrow,start__lte=next_day,emailed__isnull=True)
   class_times = class_times.exclude(session__course__active=False).exclude(session__active=False).distinct()
   if not class_times:
     return
   print "showing classes from %s to %s"%(tomorrow,next_day)
   print "reminding %s class times"%len(class_times)
   instructor_count = 0
   student_count = 0
   sent = []
   for class_time in class_times:
     instructor_count += 1
     instructor = class_time.session.user
     _dict = {
       'user': instructor,
       'la_key': LimitedAccessKey.new(instructor),
       'SITE_URL': settings.SITE_URL,
       'session': class_time.session,
       'class_time': class_time,
     }
     send_template_email("email/teaching_reminder",instructor.email,context=_dict)
     for enrollment in class_time.session.enrollment_set.all():
       student_count += 1
       user = enrollment.user
       _dict = {
         'user': user,
         'la_key': LimitedAccessKey.new(user),
         'SITE_URL': settings.SITE_URL,
         'session': class_time.session,
         'class_time': class_time,
       }
       if user.email in sent:
         continue
       sent.append(user.email)
       send_template_email("email/course_reminder",user.email,context=_dict)
     class_time.emailed = arrow.utcnow().datetime
     class_time.save()
   print "\n\n\nemailed %s instructors and %s students"%(instructor_count,student_count)
Example #11
0
def send_membership_email(*args, **kwargs):
    kwargs['from_email'] = settings.MEMBERSHIP_EMAIL
    send_template_email(*args, **kwargs)
Example #12
0
def send_membership_email(*args,**kwargs):
  kwargs['from_email'] = settings.MEMBERSHIP_EMAIL
  send_template_email(*args,**kwargs)
Example #13
0
def paypal_signal(sender, **kwargs):
    params = QueryDict(latin1_to_ascii(sender.query).replace("%FC", "u"))
    if sender.txn_type == "web_accept" and params[
            "custom"] == "support page donation":
        address = ""
        if params.get("address_street", None):
            address = "\n".join([
                params['address_name'], params['address_street'],
                "%s, %s" % (params['address_city'], params['address_state']),
                params['address_zip']
            ])
        send_template_email("email/donation_thank_you",
                            [params["payer_email"]],
                            context={
                                'params': params,
                                'address': address
                            })
        return
    if sender.txn_type in ["web_accept", "send_money"]:
        return  # payment from front page
    subscr_id = params.get('subscr_id', None) or params.get(
        'recurring_payment_id', None)
    if sender.txn_type in ['', 'cart', 'subscr_signup']:
        return  # refunds and classes and signups
    if sender.txn_id and Status.objects.filter(transaction_id=sender.txn_id):
        return  # This has already been processed
    subscription = get_subscription(params, sender)
    kwargs['subscription'] = subscription
    user, new_user = get_or_create_student(params)
    urls = "https://txrxlabs.org/admin/ipn/paypalipn/%s/" % sender.pk
    urls += "\n\n%s http://txrxlabs.org/admin/user/user/%s/" % (new_user,
                                                                user.pk)
    if subscription:
        urls += "\n\nhttps://txrxlabs.org/admin/membership/subscription/%s/" % subscription.pk

    if sender.txn_type in ['subscr_cancel']:
        subscription.force_canceled()
        paypal_flag(sender, **kwargs)
        mail_admins("Flagged %s and canceled" % sender.txn_type, urls)
        return

    elif sender.txn_type != "subscr_payment":
        return  # rest of function handles successful membership payment

    if not 'mc_gross' in params:
        mail_admins("Bad IPN", "no mc_gross in txn %s" % sender.txn_id)
        return
    amt = float(params['mc_gross'])
    if not subscription and params.get("item_number", None):
        try:
            subscription = Subscription.objects.get(pk=params['item_number'],
                                                    amount=amt)
        except Subscription.DoesNotExist:
            b = "Could not find subscription #%s for $%s and txn %s" % (
                params['item_number'], amt, sender.txn_id)
            mail_admins("Bad IPN: no subscription", b)
            return
    if not subscription:
        try:
            level = Level.objects.get(name=params.get('option_name1', ''))
        except Level.DoesNotExist:
            b = "Could not find level \"%s\" for txn %s" % (params.get(
                'option_name1', ''), sender.txn_id)
            mail_admins("Bad IPN: no level", b)
            return
        try:
            product = Product.objects.get(unit_price=amt, level=level)
        except Product.DoesNotExist:
            b = "Could not find level product \"%s\" (cost $%s) for txn %s"
            mail_admins("Bad IPN: no product", b % (level, amt, sender.txn_id))
            return
        subscription = Subscription.objects.create(user=user,
                                                   subscr_id=subscr_id,
                                                   level=product.level,
                                                   months=product.months,
                                                   amount=amt)
        Flag.objects.filter(
            subscription__user=subscription.user,
            status__in=Flag.PAYMENT_ACTIONS).update(status="paid")
        if not user.usercriterion_set.filter(
                criterion_id=settings.ORIENTATION_CRITERION_ID):
            # user has never been oriented, send welcome email and create fake safety
            user.send_welcome_email()

    status = Status.objects.create(
        transaction_id=sender.txn_id,
        subscription=subscription,
        paypalipn=sender,
        payment_method='paypal',
        amount=amt,
    )
    if not subscription.subscr_id:
        subscription.subscr_id = subscr_id
        subscription.save()
    # need to get subscription again because status forced it to recalculate
    subscription = status.subscription
    # clear out any subscription flags
    if subscription.owed <= 0:
        Flag.objects.filter(
            subscription=subscription,
            status__in=Flag.PAYMENT_ACTIONS).update(status="paid")
Example #14
0
def paypal_signal(sender,**kwargs):
  params = QueryDict(latin1_to_ascii(sender.query).replace("%FC","u"))
  if sender.txn_type == "web_accept" and params["custom"] == "support page donation":
    address = ""
    if params.get("address_street",None):
      address = "\n".join([
        params['address_name'],
        params['address_street'],
        "%s, %s"%(params['address_city'],params['address_state']),
        params['address_zip']
      ])
    send_template_email("email/donation_thank_you",[params["payer_email"]],context={'params': params,'address': address})
    return
  if sender.txn_type in ["web_accept","send_money"]:
    return # payment from front page
  subscr_id = params.get('subscr_id',None) or params.get('recurring_payment_id',None)
  if sender.txn_type in ['','cart','subscr_signup']:
    return # refunds and classes and signups
  if sender.txn_id and Status.objects.filter(transaction_id=sender.txn_id):
    return # This has already been processed
  subscription = get_subscription(params,sender)
  kwargs['subscription'] = subscription
  user,new_user = get_or_create_student(params)
  urls = "https://txrxlabs.org/admin/ipn/paypalipn/%s/"%sender.pk
  urls += "\n\n%s http://txrxlabs.org/admin/user/user/%s/"%(new_user,user.pk)
  if subscription:
    urls += "\n\nhttps://txrxlabs.org/admin/membership/subscription/%s/"%subscription.pk

  if sender.txn_type in ['subscr_cancel']:
    subscription.force_canceled()
    paypal_flag(sender,**kwargs)
    mail_admins("Flagged %s and canceled"%sender.txn_type,urls)
    return

  elif sender.txn_type != "subscr_payment":
    return # rest of function handles successful membership payment

  if not 'mc_gross' in params:
    mail_admins("Bad IPN","no mc_gross in txn %s"%sender.txn_id)
    return
  amt = float(params['mc_gross'])
  if not subscription and params.get("item_number",None):
    try:
      subscription = Subscription.objects.get(pk=params['item_number'],amount=amt)
    except Subscription.DoesNotExist:
      b = "Could not find subscription #%s for $%s and txn %s"%(params['item_number'],amt,sender.txn_id)
      mail_admins("Bad IPN: no subscription",b)
      return
  if not subscription:
    try:
      level = Level.objects.get(name=params.get('option_name1',''))
    except Level.DoesNotExist:
      b = "Could not find level \"%s\" for txn %s"%(params.get('option_name1',''),sender.txn_id)
      mail_admins("Bad IPN: no level",b)
      return
    try:
      product = Product.objects.get(unit_price=amt,level=level)
    except Product.DoesNotExist:
      b = "Could not find level product \"%s\" (cost $%s) for txn %s"
      mail_admins("Bad IPN: no product",b%(level,amt,sender.txn_id))
      return
    subscription = Subscription.objects.create(
      user=user,
      subscr_id=subscr_id,
      level=product.level,
      months=product.months,
      amount=amt
    )
    Flag.objects.filter(
      subscription__user=subscription.user,
      status__in=Flag.PAYMENT_ACTIONS
    ).update(status="paid")
    if not user.usercriterion_set.filter(criterion_id=settings.ORIENTATION_CRITERION_ID):
      # user has never been oriented, send welcome email and create fake safety
      user.send_welcome_email()

  status = Status.objects.create(
    transaction_id=sender.txn_id,
    subscription=subscription,
    paypalipn=sender,
    payment_method='paypal',
    amount=amt,
  )
  if not subscription.subscr_id:
    subscription.subscr_id = subscr_id
    subscription.save()
  # need to get subscription again because status forced it to recalculate
  subscription = status.subscription
  # clear out any subscription flags
  if subscription.owed <= 0:
    Flag.objects.filter(
      subscription=subscription,
      status__in=Flag.PAYMENT_ACTIONS
    ).update(status="paid")
Example #15
0
    def handle(self, *args, **options):
        # First people who are following classes
        notifications = Notification.objects.filter(
            emailed__isnull=True, target_type='course.session')
        students = get_user_model().objects.filter(
            id__in=set(notifications.values_list("user", flat=True)))
        count = 0
        users_count = len(students)
        if not users_count and not settings.TESTING:
            mail_admins("No classes",
                        "No new classes to notify anyone about :(")
        for user in students:
            notifications = user.notification_set.filter(
                emailed__isnull=True, target_type="course.session")
            count += notifications.count()
            sessions = [n.target for n in notifications]
            _dict = {
                'user': user,
                'la_key': LimitedAccessKey.new(user),
                'new_sessions': sessions,
                'notifications': notifications,
            }
            if user.notifysettings.new_sessions == "email":
                send_template_email("notify/email/course", [user.email],
                                    context=_dict)
            elif user.notifysettings.new_sessions == "sms":
                c = sessions[0].course.get_short_name()
                p = ""
                if len(sessions) > 1:
                    p = " and %s other classes you are interested in" % (
                        len(sessions) - 1)
                m = "There a new session of %s%s at %s. Visit %s to find out more"

                user.send_sms(m %
                              (c, p, settings.SITE_NAME, settings.NOTIFY_URL))
            notifications.update(emailed=datetime.datetime.now())
        # Now hit up enrollments that are happening tomorrow
        for relationship in ["teaching_reminder", "course_reminder"]:
            _notifications = Notification.objects.filter(
                emailed__isnull=True, target_type="course.classtime")
            _notifications = _notifications.filter(relationship=relationship)
            followers = get_user_model().objects.filter(
                id__in=set(_notifications.values_list("user", flat=True)))
            users_count = len(followers)
            for user in followers:
                notifications = user.notification_set.filter(
                    emailed__isnull=True,
                    target_type="course.classtime",
                    relationship=relationship,
                )
                count += notifications.count()
                classtimes = sorted([n.target for n in notifications],
                                    key=lambda ct: ct.start)
                if user.notifysettings.my_classes == "email":
                    _dict = {
                        'user': user,
                        'la_key': LimitedAccessKey.new(user),
                        'SITE_URL': settings.SITE_URL,
                        'notifications': notifications,
                        'first_classtime': classtimes[0],
                        'classtimes': classtimes
                    }
                    send_template_email("email/%s" % relationship,
                                        [user.email, '*****@*****.**'],
                                        context=_dict)
                elif user.notifysettings.my_classes == "sms":
                    course_name = classtimes[0].session.course.get_short_name()
                    time_s = date(classtimes[0].start, "P")
                    if len(classtimes) == 1:
                        body = "You have class tomorrow at %s: %s @ %s" % (
                            settings.SITE_NAME, course_name, time_s)
                    else:
                        body = "You have %s classes tomorrow at %s. The first is: %s @ %s" % (
                            len(classtimes), settings.SITE_NAME, course_name,
                            time_s)
                    user.send_sms(body)

                notifications.update(emailed=datetime.datetime.now())
            if options.get("verbosity") > 0:
                print "%s: Notified %s users of %s notifications" % (
                    relationship, users_count, count)
Example #16
0
  def handle(self, *args, **options):
    # First people who are following classes
    notifications = Notification.objects.filter(emailed__isnull=True,target_type='course.session')
    students = get_user_model().objects.filter(id__in=set(notifications.values_list("user",flat=True)))
    count = 0
    users_count = len(students)
    if not users_count and not settings.TESTING:
      mail_admins("No classes","No new classes to notify anyone about :(")
    for user in students:
      notifications = user.notification_set.filter(emailed__isnull=True,target_type="course.session")
      count += notifications.count()
      sessions = [n.target for n in notifications]
      _dict = {
        'user': user,
        'la_key': LimitedAccessKey.new(user),
        'new_sessions': sessions,
        'notifications': notifications,
      }
      if user.notifysettings.new_sessions == "email":
        send_template_email("notify/email/course",[user.email],context=_dict)
      elif user.notifysettings.new_sessions == "sms":
        c = sessions[0].course.get_short_name()
        p = ""
        if len(sessions) > 1:
          p = " and %s other classes you are interested in"%(len(sessions) - 1)
        m = "There a new session of %s%s at %s. Visit %s to find out more"

        user.send_sms(m%(c,p,settings.SITE_NAME,settings.NOTIFY_URL))
      notifications.update(emailed=datetime.datetime.now())
    # Now hit up enrollments that are happening tomorrow
    for relationship in ["teaching_reminder","course_reminder"]:
      _notifications = Notification.objects.filter(emailed__isnull=True,target_type="course.classtime")
      _notifications = _notifications.filter(relationship=relationship)
      followers = get_user_model().objects.filter(id__in=set(_notifications.values_list("user",flat=True)))
      users_count = len(followers)
      for user in followers:
        notifications = user.notification_set.filter(
          emailed__isnull=True,
          target_type="course.classtime",
          relationship=relationship,
        )
        count += notifications.count()
        classtimes = sorted([n.target for n in notifications],key=lambda ct: ct.start)
        if user.notifysettings.my_classes == "email":
          _dict = {
            'user': user,
            'la_key': LimitedAccessKey.new(user),
            'SITE_URL': settings.SITE_URL,
            'notifications': notifications,
            'first_classtime': classtimes[0],
            'classtimes': classtimes
          }
          send_template_email("email/%s"%relationship,[user.email,'*****@*****.**'],context=_dict)
        elif user.notifysettings.my_classes == "sms":
          course_name = classtimes[0].session.course.get_short_name()
          time_s = date(classtimes[0].start,"P")
          if len(classtimes) == 1:
            body = "You have class tomorrow at %s: %s @ %s"%(settings.SITE_NAME,course_name,time_s)
          else:
            body = "You have %s classes tomorrow at %s. The first is: %s @ %s"%(len(classtimes),settings.SITE_NAME,course_name,time_s)
          user.send_sms(body)

        notifications.update(emailed=datetime.datetime.now())
      if options.get("verbosity") > 0:
        print "%s: Notified %s users of %s notifications"%(relationship,users_count,count)