Ejemplo n.º 1
0
class RemindersListView(BaseMessagingSectionView):
    template_name = 'reminders/reminders_list.html'
    urlname = "list_reminders_new"
    page_title = ugettext_noop("Reminder Definitions")

    @method_decorator(requires_old_reminder_framework())
    @method_decorator(requires_privilege_with_fallback(privileges.OUTBOUND_SMS)
                      )
    @use_datatables
    def dispatch(self, request, *args, **kwargs):
        return super(BaseMessagingSectionView,
                     self).dispatch(request, *args, **kwargs)

    @property
    def page_url(self):
        return reverse(self.urlname, args=[self.domain])

    @property
    def can_use_survey(self):
        return can_use_survey_reminders(self.request)

    @property
    def reminders(self):
        all_handlers = CaseReminderHandler.get_handlers(
            self.domain, reminder_type_filter=REMINDER_TYPE_DEFAULT)
        if not self.can_use_survey:
            all_handlers = [
                x for x in all_handlers
                if x.method not in [METHOD_IVR_SURVEY, METHOD_SMS_SURVEY]
            ]
        for handler in all_handlers:
            yield self._fmt_reminder_data(handler)

    @property
    def page_context(self):
        return {
            'reminders':
            list(self.reminders),
            'reminders_migration_in_progress':
            (self.reminders_migration_in_progress
             and not self.new_reminders_migrator),
        }

    @property
    def reminder_id(self):
        return self.request.POST['reminderId']

    @property
    @memoized
    def reminder(self):
        return CaseReminderHandler.get(self.reminder_id)

    def _fmt_reminder_data(self, reminder):
        return {
            'id':
            reminder._id,
            'isActive':
            reminder.active,
            'caseType':
            reminder.case_type,
            'name':
            reminder.nickname,
            'url':
            reverse(EditScheduledReminderView.urlname,
                    args=[self.domain, reminder._id]),
        }

    def get_action_response(self, action):
        try:
            assert self.reminder.domain == self.domain
            assert self.reminder.doc_type == "CaseReminderHandler"
            if self.reminder.locked:
                return {
                    'success': False,
                    'locked': True,
                }

            if action in [ACTION_ACTIVATE, ACTION_DEACTIVATE]:
                self.reminder.active = (action == ACTION_ACTIVATE)
                self.reminder.save()
            elif action == ACTION_DELETE:
                self.reminder.retire()
            return {
                'success': True,
            }
        except Exception as e:
            msg = ("Couldn't process action '%s' for reminder definition" %
                   action)
            notify_exception(None,
                             message=msg,
                             details={
                                 'domain': self.domain,
                                 'handler_id': self.reminder_id,
                             })
            return {
                'success': False,
            }

    def get(self, *args, **kwargs):
        if self.reminders_migration_in_progress:
            add_migration_in_progress_message(self.request)

        return super(RemindersListView, self).get(*args, **kwargs)

    def post(self, *args, **kwargs):
        action = self.request.POST.get('action')
        if action in [ACTION_ACTIVATE, ACTION_DEACTIVATE, ACTION_DELETE]:
            if self.reminders_migration_in_progress and not self.new_reminders_migrator:
                return HttpResponse(
                    "Cannot complete action because reminders migration is in progress.",
                    status=400)
            return HttpResponse(json.dumps(self.get_action_response(action)))
        return HttpResponse(status=400)
Ejemplo n.º 2
0
class ScheduledRemindersCalendarView(BaseMessagingSectionView):
    urlname = 'scheduled_reminders'
    page_title = ugettext_noop("Reminder Calendar")
    template_name = 'reminders/partial/scheduled_reminders.html'

    @method_decorator(requires_old_reminder_framework())
    @method_decorator(requires_privilege_with_fallback(privileges.OUTBOUND_SMS)
                      )
    @method_decorator(reminders_framework_permission)
    def dispatch(self, *args, **kwargs):
        return super(BaseMessagingSectionView, self).dispatch(*args, **kwargs)

    @property
    def page_context(self):
        page_context = super(ScheduledRemindersCalendarView, self).page_context
        timezone = Domain.get_by_name(self.domain).get_default_timezone()
        reminders = CaseReminderHandler.get_all_reminders(self.domain)
        dates = []
        now = datetime.utcnow()
        timezone_now = datetime.now(timezone)
        today = timezone_now.date()

        def adjust_next_fire_to_timezone(reminder_utc):
            return ServerTime(
                reminder_utc.next_fire).user_time(timezone).done().replace(
                    tzinfo=None)

        if reminders:
            start_date = adjust_next_fire_to_timezone(reminders[0]).date()
            if today < start_date:
                start_date = today
            end_date = adjust_next_fire_to_timezone(reminders[-1]).date()
        else:
            start_date = end_date = today
        # make sure start date is a Monday and enddate is a Sunday
        start_date -= timedelta(days=start_date.weekday())
        end_date += timedelta(days=6 - end_date.weekday())
        while start_date <= end_date:
            dates.append(start_date)
            start_date += timedelta(days=1)

        reminder_data = []
        for reminder in reminders:
            handler = reminder.handler
            recipient = reminder.recipient
            recipient_desc = get_recipient_name(recipient)
            case = reminder.case

            reminder_data.append({
                "handler_name":
                handler.nickname,
                "next_fire":
                adjust_next_fire_to_timezone(reminder),
                "recipient_desc":
                recipient_desc,
                "recipient_type":
                handler.recipient,
                "case_id":
                case.case_id if case is not None else None,
                "case_name":
                case.name if case is not None else None,
            })

        page_context.update({
            'domain': self.domain,
            'reminder_data': reminder_data,
            'dates': dates,
            'today': today,
            'now': now,
            'timezone': timezone,
            'timezone_now': timezone_now,
        })
        return page_context
Ejemplo n.º 3
0
class CreateScheduledReminderView(BaseMessagingSectionView):
    urlname = 'create_reminder_schedule'
    page_title = ugettext_noop("Schedule Reminder")
    template_name = 'reminders/manage_scheduled_reminder.html'
    ui_type = UI_SIMPLE_FIXED

    @method_decorator(requires_old_reminder_framework())
    @method_decorator(reminders_framework_permission)
    @use_jquery_ui
    @use_timepicker
    @use_select2
    def dispatch(self, request, *args, **kwargs):
        if self.reminders_migration_in_progress and not self.new_reminders_migrator:
            return HttpResponseRedirect(
                reverse(RemindersListView.urlname, args=[self.domain]))
        return super(CreateScheduledReminderView,
                     self).dispatch(request, *args, **kwargs)

    @property
    def reminder_form_class(self):
        return {
            UI_COMPLEX: ComplexScheduleCaseReminderForm,
            UI_SIMPLE_FIXED: SimpleScheduleCaseReminderForm,
        }[self.ui_type]

    @property
    @memoized
    def schedule_form(self):
        if self.request.method == 'POST':
            return self.reminder_form_class(
                self.request.POST,
                domain=self.domain,
                is_previewer=self.is_previewer,
                can_use_survey=can_use_survey_reminders(self.request),
                available_languages=self.available_languages,
            )
        return self.reminder_form_class(
            is_previewer=self.is_previewer,
            domain=self.domain,
            can_use_survey=can_use_survey_reminders(self.request),
            available_languages=self.available_languages,
        )

    @property
    def available_languages(self):
        """
        Returns a the list of language codes available for the domain, or
        [] if no languages are specified.
        """
        translation_doc = StandaloneTranslationDoc.get_obj(self.domain, "sms")
        if translation_doc and translation_doc.langs:
            return translation_doc.langs
        return []

    @property
    def is_previewer(self):
        return self.request.couch_user.is_previewer()

    @property
    def parent_pages(self):
        return [
            {
                'title': _("Reminders"),
                'url': reverse(RemindersListView.urlname, args=[self.domain]),
            },
        ]

    @property
    def page_context(self):
        return {
            'form': self.schedule_form,
            'event_form': CaseReminderEventForm(ui_type=self.ui_type),
            'message_form': CaseReminderEventMessageForm(),
            'ui_type': self.ui_type,
            'available_languages': self.available_languages,
        }

    @property
    def available_case_types(self):
        case_types = []
        for app in self.apps:
            case_types.extend([m.case_type for m in app.modules])
        return set(case_types)

    @property
    def action(self):
        return self.request.POST.get('action')

    @property
    def case_type(self):
        return self.request.POST.get('caseType')

    @property
    @memoized
    def apps(self):
        return get_apps_in_domain(self.domain, include_remote=False)

    @property
    def search_term(self):
        return self.request.POST.get('term')

    @property
    def search_case_type_response(self):
        return list(self.available_case_types)

    def clean_dict_list(self, dict_list):
        """
        Takes a dict of {string: list} and returns the same result, only
        removing any duplicate entries in each of the lists.
        """
        result = {}
        for key in dict_list:
            result[key] = list(set(dict_list[key]))
        return result

    @property
    def search_form_by_id_response(self):
        """
        Returns a dict of {"id": [form unique id], "text": [full form path]}
        """
        form_unique_id = self.search_term
        try:
            form = Form.get_form(form_unique_id)
            assert form.get_app().domain == self.domain
            return {
                'text': form.full_path_name,
                'id': form_unique_id,
            }
        except:
            return {}

    @property
    def search_case_property_response(self):
        """
        Returns a dict of {case type: [case properties...]}
        """
        result = {}
        for app in self.apps:
            case_types = list(set([m.case_type for m in app.modules]))
            for case_type in case_types:
                if case_type not in result:
                    result[case_type] = ['name']
                for properties in get_case_properties(app,
                                                      [case_type]).values():
                    result[case_type].extend(properties)
        return self.clean_dict_list(result)

    def get_parent_child_types(self):
        """
        Returns a dict of {parent case type: [subcase types...]}
        """
        parent_child_types = {}
        for app in self.apps:
            for module in app.get_modules():
                case_type = module.case_type
                if case_type not in parent_child_types:
                    parent_child_types[case_type] = []
                if module.module_type == 'basic':
                    for form in module.get_forms():
                        for subcase in form.actions.subcases:
                            parent_child_types[case_type].append(
                                subcase.case_type)
                elif module.module_type == 'advanced':
                    for form in module.get_forms():
                        for subcase in form.actions.get_open_subcase_actions(
                                case_type):
                            parent_child_types[case_type].append(
                                subcase.case_type)
        return self.clean_dict_list(parent_child_types)

    @property
    def search_subcase_property_response(self):
        """
        Returns a dict of {parent case type: [subcase properties]}
        """
        result = {}
        parent_child_types = self.get_parent_child_types()
        all_case_properties = self.search_case_property_response

        for parent_type in parent_child_types:
            result[parent_type] = []
            for subcase_type in parent_child_types[parent_type]:
                result[parent_type].extend(all_case_properties[subcase_type])
        return self.clean_dict_list(result)

    @property
    def search_forms_response(self):
        forms = []
        for app in self.apps:
            for module in app.get_modules():
                for form in module.get_forms():
                    forms.append({
                        'text': form.full_path_name,
                        'id': form.unique_id,
                    })
        if not self.search_term:
            return forms
        final_forms = []
        search_terms = self.search_term.split(" ")
        for form in forms:
            matches = [t for t in search_terms if t in form['text']]
            if len(matches) == len(search_terms):
                final_forms.append(form)
        return final_forms

    def _filter_by_term(self, filter_list):
        return [f for f in filter_list if self.search_term in f]

    def _format_response(self, resp_list):
        return [{'text': r, 'id': r} for r in resp_list]

    def post(self, *args, **kwargs):
        if self.action in [
                'search_case_type',
                'search_case_property',
                'search_subcase_property',
                'search_forms',
                'search_form_by_id',
        ]:
            return HttpResponse(
                json.dumps(getattr(self, '%s_response' % self.action)))
        if self.schedule_form.is_valid():
            self.process_schedule_form()
            return HttpResponseRedirect(
                reverse(RemindersListView.urlname, args=[self.domain]))
        else:
            messages.error(self.request,
                           "There were errors saving your reminder.")
        return self.get(*args, **kwargs)

    def process_schedule_form(self):
        new_handler = CaseReminderHandler(
            use_today_if_start_date_is_blank=False)
        self.schedule_form.save(new_handler)
Ejemplo n.º 4
0
class CreateBroadcastView(BaseMessagingSectionView):
    urlname = 'add_broadcast'
    page_title = ugettext_lazy('New Broadcast')
    template_name = 'reminders/broadcast.html'
    force_create_new_broadcast = False

    @method_decorator(requires_old_reminder_framework())
    @method_decorator(requires_privilege_with_fallback(privileges.OUTBOUND_SMS)
                      )
    @use_jquery_ui
    @use_timepicker
    @use_select2
    def dispatch(self, *args, **kwargs):
        if self.reminders_migration_in_progress and not self.new_reminders_migrator:
            return HttpResponseRedirect(
                reverse(BroadcastListView.urlname, args=[self.domain]))
        return super(BaseMessagingSectionView, self).dispatch(*args, **kwargs)

    @property
    @memoized
    def project_timezone(self):
        return get_timezone_for_user(None, self.domain)

    @property
    def parent_pages(self):
        return [
            {
                'title': BroadcastListView.page_title,
                'url': reverse(BroadcastListView.urlname, args=[self.domain]),
            },
        ]

    def create_new_broadcast(self):
        return CaseReminderHandler(
            domain=self.domain,
            nickname='One-time Reminder',
            reminder_type=REMINDER_TYPE_ONE_TIME,
        )

    @property
    @memoized
    def broadcast(self):
        return self.create_new_broadcast()

    @property
    def form_kwargs(self):
        return {
            'domain': self.domain,
            'can_use_survey': can_use_survey_reminders(self.request),
        }

    @property
    def form_class(self):
        if toggles.EWS_BROADCAST_BY_ROLE.enabled(self.domain):
            return EWSBroadcastForm
        else:
            return BroadcastForm

    @property
    @memoized
    def broadcast_form(self):
        if self.request.method == 'POST':
            return self.form_class(self.request.POST, **self.form_kwargs)
        else:
            return self.form_class(**self.form_kwargs)

    @property
    def page_context(self):
        return {
            'form': self.broadcast_form,
        }

    def save_model(self, broadcast, form):
        broadcast.default_lang = 'xx'
        broadcast.method = form.cleaned_data.get('content_type')
        broadcast.recipient = form.cleaned_data.get('recipient_type')
        broadcast.start_condition_type = ON_DATETIME
        broadcast.start_datetime = form.cleaned_data.get('datetime')
        broadcast.start_offset = 0
        broadcast.events = [
            CaseReminderEvent(
                day_num=0,
                fire_time=time(0, 0),
                form_unique_id=form.cleaned_data.get('form_unique_id'),
                message=({
                    broadcast.default_lang:
                    form.cleaned_data.get('message')
                } if form.cleaned_data.get('message') else {}),
                subject=({
                    broadcast.default_lang:
                    form.cleaned_data.get('subject')
                } if form.cleaned_data.get('subject') else {}),
                callback_timeout_intervals=[],
            )
        ]
        broadcast.schedule_length = 1
        broadcast.event_interpretation = EVENT_AS_OFFSET
        broadcast.max_iteration_count = 1
        broadcast.sample_id = form.cleaned_data.get('case_group_id')
        broadcast.user_group_id = form.cleaned_data.get('user_group_id')
        broadcast.location_ids = form.cleaned_data.get('location_ids')
        broadcast.include_child_locations = form.cleaned_data.get(
            'include_child_locations')
        if toggles.EWS_BROADCAST_BY_ROLE.enabled(self.domain):
            broadcast.user_data_filter = form.get_user_data_filter()
        broadcast.save()

    def post(self, request, *args, **kwargs):
        if self.broadcast_form.is_valid():
            if self.force_create_new_broadcast:
                broadcast = self.create_new_broadcast()
            else:
                broadcast = self.broadcast

            self.save_model(broadcast, self.broadcast_form)
            return HttpResponseRedirect(
                reverse(BroadcastListView.urlname, args=[self.domain]))
        return self.get(request, *args, **kwargs)
Ejemplo n.º 5
0
class BroadcastListView(BaseMessagingSectionView,
                        DataTablesAJAXPaginationMixin):
    template_name = 'reminders/broadcasts_list.html'
    urlname = 'list_broadcasts'
    page_title = ugettext_lazy('Broadcasts')

    LIST_UPCOMING = 'list_upcoming'
    LIST_PAST = 'list_past'
    DELETE_BROADCAST = 'delete_broadcast'

    @method_decorator(requires_old_reminder_framework())
    @method_decorator(requires_privilege_with_fallback(privileges.OUTBOUND_SMS)
                      )
    @use_datatables
    def dispatch(self, request, *args, **kwargs):
        return super(BroadcastListView, self).dispatch(request, *args,
                                                       **kwargs)

    @property
    def page_context(self):
        return {
            'reminders_migration_in_progress':
            (self.reminders_migration_in_progress
             and not self.new_reminders_migrator),
        }

    @property
    @memoized
    def project_timezone(self):
        return get_timezone_for_user(None, self.domain)

    def format_recipients(self, broadcast):
        reminders = broadcast.get_reminders()
        if len(reminders) == 0:
            return _('(none)')
        return get_recipient_name(reminders[0].recipient, include_desc=False)

    def format_content(self, broadcast):
        if broadcast.method == METHOD_SMS_SURVEY:
            content = get_form_name(broadcast.events[0].form_unique_id)
        else:
            message = broadcast.events[0].message[broadcast.default_lang]
            if len(message) > 50:
                content = '"%s..."' % message[:47]
            else:
                content = '"%s"' % message
        return content

    def format_broadcast_name(self, broadcast):
        user_time = ServerTime(broadcast.start_datetime).user_time(
            self.project_timezone)
        return user_time.ui_string(SERVER_DATETIME_FORMAT)

    def format_broadcast_data(self, ids):
        broadcasts = CaseReminderHandler.get_handlers_from_ids(ids)
        result = []
        for broadcast in broadcasts:
            display = self.format_broadcast_name(broadcast)
            result.append([
                display,
                self.format_recipients(broadcast),
                self.format_content(broadcast),
                broadcast._id,
                reverse(EditBroadcastView.urlname,
                        args=[self.domain, broadcast._id]),
                reverse(CopyBroadcastView.urlname,
                        args=[self.domain, broadcast._id]),
            ])
        return result

    def get_broadcast_ajax_response(self, upcoming=True):
        """
        upcoming - True to include only upcoming broadcasts, False to include
                   only past broadcasts.
        """
        if upcoming:
            ids = CaseReminderHandler.get_upcoming_broadcast_ids(self.domain)
        else:
            ids = CaseReminderHandler.get_past_broadcast_ids(self.domain)

        total_records = len(ids)
        ids = ids[self.display_start:self.display_start + self.display_length]
        data = self.format_broadcast_data(ids)
        return self.datatables_ajax_response(data, total_records)

    def delete_broadcast(self, broadcast_id):
        try:
            broadcast = CaseReminderHandler.get(broadcast_id)
        except:
            raise Http404()

        if broadcast.doc_type != 'CaseReminderHandler' or broadcast.domain != self.domain:
            raise Http404()

        broadcast.retire()
        return HttpResponse()

    def get(self, *args, **kwargs):
        action = self.request.GET.get('action')
        if action in (self.LIST_UPCOMING, self.LIST_PAST):
            upcoming = (action == self.LIST_UPCOMING)
            return self.get_broadcast_ajax_response(upcoming)
        else:
            if self.reminders_migration_in_progress:
                add_migration_in_progress_message(self.request)
            return super(BroadcastListView, self).get(*args, **kwargs)

    def post(self, *args, **kwargs):
        action = self.request.POST.get('action')
        if action == self.DELETE_BROADCAST:
            if self.reminders_migration_in_progress and not self.new_reminders_migrator:
                return HttpResponse(
                    "Cannot complete action because reminders migration is in progress.",
                    status=400)
            return self.delete_broadcast(
                self.request.POST.get('broadcast_id', None))
        else:
            return HttpResponse(status=400)