예제 #1
0
def get_conditional_alert_rows(domain):
    translated_rows = []
    untranslated_rows = []

    langs = get_language_list(domain)
    for rule in get_conditional_alerts_queryset_by_domain(domain):
        schedule = rule.get_messaging_rule_schedule()
        events = schedule.memoized_events
        send_frequency = ScheduleForm.get_send_frequency_by_ui_type(
            schedule.ui_type)

        # Custom schedules may have multiple events each with different content
        # Non-custom schedules may have multiple events (e.g., daily schedule sent MWF) but each
        # event will have identical content, so only include the first one
        if send_frequency not in (ScheduleForm.SEND_CUSTOM_DAILY,
                                  ScheduleForm.SEND_CUSTOM_IMMEDIATE):
            events = [events[0]]

        for event in events:
            common_columns = [rule.pk, rule.name]
            if UntranslatedConditionalAlertUploader.event_is_relevant(event):
                untranslated_rows.append(common_columns +
                                         [event.content.message.get('*', '')])
            elif TranslatedConditionalAlertUploader.event_is_relevant(event):
                translated_rows.append(
                    common_columns +
                    [event.content.message.get(lang, '') for lang in langs])

    return (translated_rows, untranslated_rows)
예제 #2
0
    def save_rule_messages(self, rule, rows):
        schedule = rule.get_schedule()
        send_frequency = ScheduleForm.get_send_frequency_by_ui_type(
            schedule.ui_type)

        # Iterate over rule's events
        if send_frequency not in (ScheduleForm.SEND_CUSTOM_DAILY,
                                  ScheduleForm.SEND_CUSTOM_IMMEDIATE):
            # For standard schedules, the rule may have multiple events (e.g., a daily rule run Mon and Tues
            # will have 2 events), but all events will have the same message, so we only need to look at the
            # first event. Since there's only one message, the user is free to move it between sheets.
            events = [rule.get_schedule().memoized_events[0]]
            allow_sheet_swap = True
        else:
            # For custom schedules, each event has its own message, so we need to look at all of them, and they may
            # be a mix of translated and untranslated.
            # If all messages are on one sheet: The user may update any or all and may move ALL of them to the
            #   other sheet. We assume that the order of rows is the same as the rule's order of events.
            # If messages are split between sheets: The user may only make updates on one sheet (once the first
            #   sheet is updated, the rule will begin processing, so the second sheet's updates will fail). Again,
            #   we assume the order of rows matches the order of events (with the other sheet's rows interleaved).
            #   The user may not move messages between sheets, since we can't match events to messages.
            events = rule.get_schedule().memoized_events
            allow_sheet_swap = len(rows) == len(events)

        message_dirty = False
        new_messages = []
        row_index = 0
        for index, event in enumerate(events):
            old_message = event.content.message
            new_message = copy(old_message)
            if self.event_is_relevant(event) or allow_sheet_swap:
                new_message = self.update_message(new_message, rows[row_index])
                message_dirty = message_dirty or old_message != new_message
                row_index += 1
            new_messages.append(new_message)

        if message_dirty:
            if any(True for message in new_messages
                   for value in message.values() if not value):
                raise RuleUpdateError(_("Missing message"))

        {
            ScheduleForm.SEND_IMMEDIATELY: self._save_immediate_schedule,
            ScheduleForm.SEND_DAILY: self._save_daily_schedule,
            ScheduleForm.SEND_WEEKLY: self._save_weekly_schedule,
            ScheduleForm.SEND_MONTHLY: self._save_monthly_schedule,
            ScheduleForm.SEND_CUSTOM_IMMEDIATE:
            self._save_custom_immediate_schedule,
            ScheduleForm.SEND_CUSTOM_DAILY: self._save_custom_daily_schedule,
        }[send_frequency](schedule, new_messages)

        return message_dirty
예제 #3
0
    def upload(self, workbook):
        self.msgs = []
        success_count = 0
        worksheet = workbook.get_worksheet(title=self.sheet_name)

        errors = self.get_worksheet_errors(worksheet)
        if errors:
            return errors

        # Most rules are represented by a single row, but rules with custom schedules have one row per event.
        # Read through the worksheet, grouping rows by rule id and caching rule definitions.
        condensed_rows = defaultdict(list)
        rules_by_id = {}

        for index, row in enumerate(worksheet,
                                    start=2):  # one-indexed, plus header row
            if not row.get('id', None):
                self.msgs.append(
                    (messages.error,
                     _("Row {index} in '{sheet_name}' sheet is missing "
                       "an id.").format(index=index,
                                        sheet_name=self.sheet_name)))
                continue

            if row['id'] in condensed_rows:
                # This is the 2nd (or 3rd, 4th, ...) row for a rule we've already seen
                condensed_rows[row['id']].append(row)
                continue

            try:
                rule = AutomaticUpdateRule.objects.get(
                    pk=row['id'],
                    domain=self.domain,
                    workflow=AutomaticUpdateRule.WORKFLOW_SCHEDULING,
                    deleted=False,
                )
            except AutomaticUpdateRule.DoesNotExist:
                self.msgs.append((
                    messages.error,
                    _("""Could not find rule for row {index} in '{sheet_name}' sheet, """
                      """with id {id}""").format(index=index,
                                                 id=row['id'],
                                                 sheet_name=self.sheet_name)))
                continue

            if rule.locked_for_editing:
                self.msgs.append((
                    messages.error,
                    _("Row {index} in '{sheet_name}' sheet, with rule id {id}, "
                      "is currently processing and cannot be updated.").format(
                          index=index,
                          id=row['id'],
                          sheet_name=self.sheet_name)))
                continue

            if not isinstance(
                    rule.get_messaging_rule_schedule().memoized_events[0].
                    content, SMSContent):
                self.msgs.append((
                    messages.error,
                    _("Row {index} in '{sheet_name}' sheet, with rule id {id}, "
                      "does not use SMS content.").format(
                          index=index,
                          id=row['id'],
                          sheet_name=self.sheet_name)))
                continue

            rules_by_id[row['id']] = rule
            condensed_rows[row['id']].append(row)

        # Update the condensed set of rules
        for rule_id, rows in condensed_rows.items():
            rule = rules_by_id[rule_id]
            schedule = rule.get_messaging_rule_schedule()
            send_frequency = ScheduleForm.get_send_frequency_by_ui_type(
                schedule.ui_type)

            if send_frequency in (ScheduleForm.SEND_CUSTOM_DAILY,
                                  ScheduleForm.SEND_CUSTOM_IMMEDIATE):
                # Check that user provided one row for each event in the custom schedule
                all_events = rule.get_messaging_rule_schedule().memoized_events
                expected = len(
                    [e for e in all_events if self.event_is_relevant(e)])
                actual = len(rows)
                if expected != actual and actual != len(all_events):
                    self.msgs.append((
                        messages.error,
                        _("Could not update rule with id {id} in '{sheet_name}' "
                          "sheet: expected {expected} row(s) but found "
                          "{actual}.").format(id=rule.id,
                                              sheet_name=self.sheet_name,
                                              expected=expected,
                                              actual=actual)))
                    continue

            with transaction.atomic():
                try:
                    dirty = self.update_rule(rule, rows)
                except RuleUpdateError as e:
                    self.msgs.append((
                        messages.error,
                        _("Error updating rule with id {id} in '{sheet_name}' "
                          "sheet: {detail}").format(id=rule.id,
                                                    sheet_name=self.sheet_name,
                                                    detail=str(e))))
                    continue

                if dirty:
                    rule.save()
                    initiate_messaging_rule_run(rule)
                    success_count += 1

        self.msgs.append(
            (messages.success,
             _("Updated {count} rule(s) in '{sheet_name}' sheet").format(
                 count=success_count, sheet_name=self.sheet_name)))

        return self.msgs