示例#1
0
def delete_domain_membership(request, domain, couch_user_id, domain_name):
    removing_self = request.couch_user.get_id == couch_user_id
    user = WebUser.get_by_user_id(couch_user_id, domain_name)

    # don't let a user remove another user's domain membership if they're not the admin of the domain or a superuser
    if not removing_self and not (request.couch_user.is_domain_admin(domain_name) or request.couch_user.is_superuser):
        messages.error(request, _("You don't have the permission to remove this user's membership"))

    elif user.is_domain_admin(domain_name): # don't let a domain admin be removed from the domain
        if removing_self:
            error_msg = ugettext_noop("Unable remove membership because you are the admin of %s" % domain_name)
        else:
            error_msg = ugettext_noop("Unable remove membership because %(user)s is the admin of %(domain)s" % {
                'user': user.username,
                'domain': domain_name
            })
        messages.error(request, error_msg)
        
    else:
        user.delete_domain_membership(domain_name)
        user.save()

        if removing_self:
            success_msg = ugettext_noop("You are no longer a part of the %s project space" % domain_name)
        else:
            success_msg = ugettext_noop("%(user)s is no longer a part of the %(domain)s project space" % {
                'user': user.username,
                'domain': domain_name
            })
        messages.success(request, success_msg)

        if removing_self and not user.is_member_of(domain):
            return HttpResponseRedirect(reverse("homepage"))

    return HttpResponseRedirect(reverse("user_account", args=(domain, couch_user_id)))
示例#2
0
文件: models.py 项目: RazvanRzv/wouso
 def handle_result(self):
     if self.challenge.status == "D":
         action_msg = "chall-draw"
         signal_msg = ugettext_noop("draw result between {user_from} and {user_to}:\n{extra}")
         signals.addActivity.send(
             sender=None,
             user_from=self.challenge.user_to.user,
             user_to=self.challenge.user_from.user,
             message=signal_msg,
             arguments=dict(
                 user_to=self.challenge.user_to,
                 user_from=self.challenge.user_from,
                 extra=self.challenge.extraInfo(self.challenge.user_from, self.challenge.user_to),
             ),
             action=action_msg,
             game=ChallengeGame.get_instance(),
         )
     elif self.challenge.status == "P":
         action_msg = "chall-won"
         signal_msg = ugettext_noop("won challenge with {user_lost}: {extra}")
         signals.addActivity.send(
             sender=None,
             user_from=self.challenge.user_won.user,
             user_to=self.challenge.user_lost.user,
             message=signal_msg,
             arguments=dict(
                 user_lost=self.challenge.user_lost,
                 id=self.challenge.id,
                 extra=self.challenge.extraInfo(self.challenge.user_won, self.challenge.user_lost),
             ),
             action=action_msg,
             game=ChallengeGame.get_instance(),
         )
示例#3
0
 def track_changes(self, user_making_changes):
     changes = []
     track_changes_of = [
         ('title', ugettext_noop('Gig name')),
         ('date', ugettext_noop('Gig date')),
         ('description', ugettext_noop('Description')),
     ]
     for field, verbose_name in track_changes_of:
         oldval = str(self._pristine[field] or '')
         newval = str(getattr(self, field))
         if oldval != newval:
             changes.append({
                 'title': verbose_name,
                 'title_translatable': True,
                 'prev': oldval,
                 'new': newval
             })
     if not changes:
         return
     action = (ugettext_noop('%(who)s (f) edited gig %(when)s')
               if user_making_changes.profile.gender == 'f' else
               ugettext_noop('%(who)s (m) edited gig %(when)s'))
     info = {'action': action, 'changes': changes}
     Comment.objects.create(
         gig=self, song=None, author=user_making_changes,
         text=json.dumps(info), comment_type=Comment.CT_GIG_EDIT,
     )
示例#4
0
def zorna_post_syncdb(app, created_models, verbosity, **kwargs):
    if UserGroup.objects.count() > 0:
        return
    p = UserGroup(name=ugettext_noop(u"Public"), parent=None)
    p.save()
    UserGroup(name=ugettext_noop(u"Anonymous"), parent=p).save()
    UserGroup(name=ugettext_noop(u"Registered"), parent=p).save()
示例#5
0
    def post(self, request):
        """
        POST /api/bookmarks/v1/bookmarks/
        Request data: {"usage_id": "<usage-id>"}
        """

        if not request.data:
            return self.error_response(ugettext_noop(u"No data provided."), DEFAULT_USER_MESSAGE)

        usage_id = request.data.get("usage_id", None)
        if not usage_id:
            return self.error_response(ugettext_noop(u"Parameter usage_id not provided."), DEFAULT_USER_MESSAGE)

        try:
            usage_key = UsageKey.from_string(unquote_slashes(usage_id))
        except InvalidKeyError:
            error_message = ugettext_noop(u"Invalid usage_id: {usage_id}.").format(usage_id=usage_id)
            log.error(error_message)
            return self.error_response(error_message, DEFAULT_USER_MESSAGE)

        try:
            bookmark = api.create_bookmark(user=self.request.user, usage_key=usage_key)
        except ItemNotFoundError:
            error_message = ugettext_noop(u"Block with usage_id: {usage_id} not found.").format(usage_id=usage_id)
            log.error(error_message)
            return self.error_response(error_message, DEFAULT_USER_MESSAGE)
        except BookmarksLimitReachedError:
            error_message = ugettext_noop(
                u"You can create up to {max_num_bookmarks_per_course} bookmarks."
                u" You must remove some bookmarks before you can add new ones."
            ).format(max_num_bookmarks_per_course=settings.MAX_BOOKMARKS_PER_COURSE)
            log.info(u"Attempted to create more than %s bookmarks", settings.MAX_BOOKMARKS_PER_COURSE)
            return self.error_response(error_message)

        return Response(bookmark, status=status.HTTP_201_CREATED)
示例#6
0
    def support(self, request, pk=None):
        """
        Special view endpoint to support a motion or withdraw support
        (unsupport).

        Send POST to support and DELETE to unsupport.
        """
        # Retrieve motion and allowed actions.
        motion = self.get_object()

        # Support or unsupport motion.
        if request.method == 'POST':
            # Support motion.
            if not (motion.state.allow_support and
                    config['motions_min_supporters'] > 0 and
                    not motion.is_submitter(request.user) and
                    not motion.is_supporter(request.user)):
                raise ValidationError({'detail': _('You can not support this motion.')})
            motion.supporters.add(request.user)
            motion.write_log([ugettext_noop('Motion supported')], request.user)
            # Send new supporter via autoupdate because users without permission
            # to see users may not have it but can get it now.
            inform_changed_data([request.user])
            message = _('You have supported this motion successfully.')
        else:
            # Unsupport motion.
            # request.method == 'DELETE'
            if not motion.state.allow_support or not motion.is_supporter(request.user):
                raise ValidationError({'detail': _('You can not unsupport this motion.')})
            motion.supporters.remove(request.user)
            motion.write_log([ugettext_noop('Motion unsupported')], request.user)
            message = _('You have unsupported this motion successfully.')

        # Initiate response.
        return Response({'detail': message})
示例#7
0
 def joined_part(cls, user, part, old_performers, *, changed_by=None):
     SongWatcher.objects.update_or_create(song=part.song, user=user)
     action = (ugettext_noop('%(who)s (f) joined a song part %(when)s')
               if user.profile.gender == 'f' else
               ugettext_noop('%(who)s (m) joined a song part %(when)s'))
     return cls._part_participation_base(action, user, part, old_performers,
                                         changed_by=changed_by)
示例#8
0
    def support(self, request, pk=None):
        """
        Special view endpoint to support a motion or withdraw support
        (unsupport).

        Send POST to support and DELETE to unsupport.
        """
        # Retrieve motion and allowed actions.
        motion = self.get_object()
        allowed_actions = motion.get_allowed_actions(request.user)

        # Support or unsupport motion.
        if request.method == 'POST':
            # Support motion.
            if not allowed_actions['support']:
                raise ValidationError({'detail': _('You can not support this motion.')})
            motion.supporters.add(request.user)
            motion.write_log([ugettext_noop('Motion supported')], request.user)
            message = _('You have supported this motion successfully.')
        else:
            # Unsupport motion.
            # request.method == 'DELETE'
            if not allowed_actions['unsupport']:
                raise ValidationError({'detail': _('You can not unsupport this motion.')})
            motion.supporters.remove(request.user)
            motion.write_log([ugettext_noop('Motion unsupported')], request.user)
            message = _('You have unsupported this motion successfully.')

        # Initiate response.
        return Response({'detail': message})
示例#9
0
文件: sm.py 项目: damianr13/wouso
def update_points(player, game):
    level = God.get_level_for_points(player.points)

    if level == player.level_no:
        return

	arguments = dict(level=level)
    if level < player.level_no:
        action_msg = 'level-downgrade'
        signal_msg = ugettext_noop("downgraded to level {level}")
		this_game = game
	else:
        action_msg = 'level-upgrade'
        # Check if the user has previously reached this level
        if level > player.max_level:
            # Update the maximum reached level
            player.max_level = level
            # Offer the corresponding amount of gold
            score(player, None, 'level-gold', external_id=level, level=level)

            signal_msg = ugettext_noop("upgraded to level {level} and received {amount} gold")
            amount = calculate('level-gold', level=level).get('gold', 0)
            arguments['amount'] = amount
        else:
            # The user should not receive additional gold
            signal_msg = ugettext_noop("upgraded back to level {level}")
		this_game = None

	signals.addActivity.send(sender=None, user_from=player,
                            user_to=player, message=signal_msg,
                            arguments=dict(level=level),
                            game=game, action=action_msg)
示例#10
0
    def __init__(self, filepath, seaf=None, repo_id=None):
        """Initialize a form for the file `filepath`.

            If seaf is a Seafile instance, repo_id must be the
            Seafile identifier of the repository where `filepath` is.

            If seaf is None, load `filepath` from the local filesystem
        """
        # source properties
        self.filepath = filepath
        self.seaf = seaf
        self.repo_id = repo_id
        self.loaded = False

        # form properties
        self.title = None
        self.description = None
        self.fields = None
        self.data = None
        # Translators: ODS view mode
        self._view_as_values = (ugettext_noop('table'), ugettext_noop('form'))
        self._view_as_l10n = [_(v) for v in self._view_as_values]
        self.view_as = None # ('table' or 'form')
        # Translators: ODS edit, yes or no
        self._edit_values = (ugettext_noop('yes'), ugettext_noop('no'))
        self._edit_val10n = [_(v) for v in self._edit_values]
        self.edit = None
        
        # cached items
        self.mtime = None
        self._odsfile = None
        self._first_empty_row = None
示例#11
0
    def support(self, request, pk=None):
        """
        Special view endpoint to support a motion or withdraw support
        (unsupport).

        Send POST to support and DELETE to unsupport.
        """
        # Retrieve motion and allowed actions.
        motion = self.get_object()

        # Support or unsupport motion.
        if request.method == "POST":
            # Support motion.
            if not (
                motion.state.allow_support
                and config["motions_min_supporters"] > 0
                and not motion.is_submitter(request.user)
                and not motion.is_supporter(request.user)
            ):
                raise ValidationError({"detail": _("You can not support this motion.")})
            motion.supporters.add(request.user)
            motion.write_log([ugettext_noop("Motion supported")], request.user)
            message = _("You have supported this motion successfully.")
        else:
            # Unsupport motion.
            # request.method == 'DELETE'
            if not motion.state.allow_support or not motion.is_supporter(request.user):
                raise ValidationError({"detail": _("You can not unsupport this motion.")})
            motion.supporters.remove(request.user)
            motion.write_log([ugettext_noop("Motion unsupported")], request.user)
            message = _("You have unsupported this motion successfully.")

        # Initiate response.
        return Response({"detail": message})
示例#12
0
文件: models.py 项目: jabber-at/hp
    def add_gpg_key(self, keys, fingerprint, address):
        if isinstance(keys, str):
            keys = keys.encode('utf-8')  # convert to bytes

        imported = []

        with self.gpg_keyring(init=False) as backend:
            for key in keys.split(_gpg_key_delimiter):
                try:
                    imp_key = backend.import_key(keys)[0]
                    imported.append((key, imp_key.fp, imp_key.expires))
                except Exception as e:
                    log.exception(e)
                    err = ugettext_noop('Error importing GPG key.')
                    self.log(err, address=address)  # log entry in "Recent activity"
                    self.message(messages.ERROR, err)  # message to user
                    raise

        for key, fp, expires in imported:
            if expires:  # None if the key does not expire
                expires = timezone.make_aware(expires)

            # Create or update the GPG key
            dbkey, created = GpgKey.objects.update_or_create(
                user=self, fingerprint=fp, defaults={'key': key, 'expires': expires, })

            payload = {'fingerprint': fp, }
            if created is True:
                message = ugettext_noop('Added GPG key 0x%(fingerprint)s.')
            else:
                message = ugettext_noop('Updated GPG key 0x%(fingerprint)s.')

            self.log(message, address=address, **payload)
            self.message(messages.INFO, message, **payload)
示例#13
0
def somebody_commented_your_fruit(comment, comment_type, object_id, **kwargs):
    """
    Notify users that there is a new comment under their marker.
    """
    if comment_type.model == 'fruit':
        fruit = comment_type.get_object_for_this_type(pk=object_id)
        if fruit.user != comment.author:
            if not comment.complaint:
                msg_template = ugettext_noop(
                    'User <a href="{user_url}">{user_name}</a> '
                    'posted a <a href="{comment_url}">comment</a> '
                    'under your <a href="{fruit_url}">marker</a>.'
                )
            else:
                msg_template = ugettext_noop(
                    'User <a href="{user_url}">{user_name}</a> '
                    '<strong>posted a <a href="{comment_url}">complaint</a></strong> '
                    'under your <a href="{fruit_url}">marker</a>.'
                )
            context = dict(
                user_name=comment.author.username,
                user_url=comment.author.get_absolute_url(),
                comment_url=comment.get_absolute_url(),
                fruit_url=fruit.get_absolute_url(),
            )
            fruit.user.send_message(msg_template, context=context, system=True)
示例#14
0
 def get_notification_message_submission_judged(self, submission):
     if submission.score is not None and submission.score.accepted:
         return ugettext_noop("Your submission for task %(short_name)s"
                  " is accepted. Congratulations!")
     else:
         return ugettext_noop("Your submission for task %(short_name)s"
                  " is not accepted.")
示例#15
0
文件: models.py 项目: wowone/songbook
 def edited_part_participation(cls, user, part, old_performers):
     action = (
         ugettext_noop('%(who)s (f) edited part participation %(when)s')
         if user.profile.gender == 'f' else
         ugettext_noop('%(who)s (m) edited part participation %(when)s')
     )
     return cls._part_participation_base(action, user, part, old_performers)
示例#16
0
文件: sm.py 项目: Ciocirlan/wouso
def update_points(player, game):
    level = God.get_level_for_points(player.points)
    if level != player.level_no:
        if level < player.level_no:
            amount = calculate('level-gold', level=player.level_no).get('gold', 0)
            action_msg = 'gold-lost'
            signal_msg = ugettext_noop("downgraded to level {level} and lost {amount} gold")
            rollback(player, None, 'level-gold', external_id=player.level_no)
            signals.addActivity.send(sender=None, user_from=player,
                                user_to=player, message=signal_msg,
                                arguments=dict(level=level, amount=amount),
                                game=game, action=action_msg)
        else:

            amount = calculate('level-gold', level=level)
            # Check if the user has previously reached this level
            if level > player.max_level:
                # Update the maximum reached level
                player.max_level = level
                # Offer the corresponding amount of gold
                score(player, None, 'level-gold', external_id=level, level=level)
            else:
                # The user should not receive additional gold
                amount['gold'] = 0
            signal_msg = ugettext_noop("upgraded to level {level} and received {amount} gold")
            action_msg = 'gold-won'
            signals.addActivity.send(sender=None, user_from=player,
                    user_to=player, message=signal_msg,
                                arguments=dict(level=level, amount=amount['gold']),
                                game=None, action=action_msg)
        player.level_no = level
        player.save()
示例#17
0
	def save_model(self, request, obj, form, change):
		pin = form.cleaned_data['pin_change']
		pin_empty = form.cleaned_data['pin_empty']

		if pin_empty:
			obj.clear_pin()
		else:
			if pin is not None and len(pin) != 0:
				obj.set_pin(pin)

		PAYOUT_SUBJECT = ugettext_noop('Payout')
		DEPOSIT_SUBJECT = ugettext_noop('Deposit')
		DESCRIPTION = ugettext_noop('Authorized by %(first)s %(last)s')

		amount = form.cleaned_data['credit_change']
		comment = form.cleaned_data['credit_change_comment']

		if amount is not None and amount != 0:
			if amount > 0:
				subject = DEPOSIT_SUBJECT
			else:
				subject = PAYOUT_SUBJECT

			desc = DESCRIPTION % {'first': request.user.first_name,
			                      'last': request.user.last_name}
			if comment is not None and len(comment) > 0:
				desc += ' (%s)' % (comment)
			obj.change_credit(amount, subject, desc)

		# Make sure the object is saved in any case
		obj.save()
示例#18
0
文件: sm.py 项目: andreip/wouso
def update_points(player, game):
    level = God.get_level_for_points(player.points)
    if level != player.level_no:
        if level < player.level_no:
            signal_msg = ugettext_noop("downgraded to level {level}")
            signals.addActivity.send(
                sender=None,
                user_from=player,
                user_to=player,
                message=signal_msg,
                arguments=dict(level=level),
                game=game,
            )
        else:
            amount = calculate("level-gold", level=level)
            signal_msg = ugettext_noop("upgraded to level {level} and received {amount} gold")
            score(player, None, "level-gold", level=level)
            signals.addActivity.send(
                sender=None,
                user_from=player,
                user_to=player,
                message=signal_msg,
                arguments=dict(level=level, amount=amount["gold"]),
                game=None,
            )
        player.level_no = level
        player.save()
示例#19
0
    def update(self, request, *args, **kwargs):
        """
        Customized view endpoint to update a motion.

        Checks also whether the requesting user can update the motion. He
        needs at least the permissions 'motions.can_see' (see
        self.check_view_permissions()). Also check manage permission or
        submitter and state.
        """
        # Get motion.
        motion = self.get_object()

        # Check permissions.
        if (not has_perm(request.user, 'motions.can_manage') and
                not (motion.is_submitter(request.user) and motion.state.allow_submitter_edit) and
                not has_perm(request.user, 'motions.can_see_and_manage_comments')):
            self.permission_denied(request)

        # Check permission to send only some data.
        if not has_perm(request.user, 'motions.can_manage'):
            # Remove fields that the user is not allowed to change.
            # The list() is required because we want to use del inside the loop.
            keys = list(request.data.keys())
            whitelist = [
                'comments',  # This is checked later.
            ]
            # Add title, text and reason to the whitelist only, if the user is the submitter.
            if motion.is_submitter(request.user) and motion.state.allow_submitter_edit:
                whitelist.extend((
                    'title',
                    'text',
                    'reason',
                ))
            for key in keys:
                if key not in whitelist:
                    del request.data[key]
        if not has_perm(request.user, 'motions.can_see_and_manage_comments'):
            try:
                del request.data['comments']
            except KeyError:
                # No comments here. Just do nothing.
                pass

        # Validate data and update motion.
        serializer = self.get_serializer(
            motion,
            data=request.data,
            partial=kwargs.get('partial', False))
        serializer.is_valid(raise_exception=True)
        updated_motion = serializer.save(disable_versioning=request.data.get('disable_versioning'))

        # Write the log message, check removal of supporters and initiate response.
        # TODO: Log if a version was updated.
        updated_motion.write_log([ugettext_noop('Motion updated')], request.user)
        if (config['motions_remove_supporters'] and updated_motion.state.allow_support and
                not has_perm(request.user, 'motions.can_manage')):
            updated_motion.supporters.clear()
            updated_motion.write_log([ugettext_noop('All supporters removed')], request.user)
        return Response(serializer.data)
示例#20
0
def book_order(request):
    """
    Book an order: send it to the dispatcher to get an order assignment,
    then pass the assignment to the station manager.
    """
    order_id = int(request.POST["order_id"])
    logging.info("book_order_task: %d" % order_id)
    order = get_object_or_404(Order, id=order_id)
    passenger = order.passenger

    # if this is the first order of this passenger, connect him with the station that originated the order
    if order.originating_station and passenger.orders.count() == 1:
        logging.info("assigning passenger %s to station %s" % (passenger, order.originating_station))
        passenger.originating_station = order.originating_station
        if not passenger.default_station:
            passenger.default_station = order.originating_station

        passenger.save()

    sorry_msg = ugettext_noop("We're sorry, but we could not find a taxi for you") # use dummy ugettext for makemessages)

    # check if dispatching should stop and return an answer to the user
    if (utc_now() - order.create_date).seconds > ORDER_HANDLE_TIMEOUT:
        try:
            order.change_status(new_status=TIMED_OUT)
            send_msg_to_passenger(passenger, translate_to_lang(sorry_msg, order.language_code))
            logging.warning("order time out: %d" % order_id)
            response = HttpResponse(ORDER_TIMEOUT)
        except UpdateStatusError:
            logging.error("book_order failed: cannot set order [%d] status to %s" % (order.id, "TIME_OUT"))
    else:
        try:
            # choose an assignment for the order and push it to the relevant workstation
            order_assignment = dispatcher.assign_order(order)
            push_order(order_assignment)
            enqueue_redispatch_orders(order_assignment, ORDER_TEASER_TIMEOUT, redispatch_pending_orders)
            response = HttpResponse(ORDER_HANDLED)

        except NoWorkStationFoundError:
            try:
                order.change_status(new_status=FAILED)
                send_msg_to_passenger(passenger, translate_to_lang(sorry_msg, order.language_code)) # use dummy ugettext for makemessages

                log_event(EventType.ORDER_FAILED, order=order, passenger=order.passenger)
                logging.warning("no matching workstation found for: %d" % order_id)
                response = HttpResponse(NO_MATCHING_WORKSTATIONS_FOUND)
            except UpdateStatusError:
                logging.error("book_order failed: cannot set order [%d] status to %s" % (order.id, "FAILED"))

        except Exception, e:
            try:
                order.change_status(new_status=ERROR)
                send_msg_to_passenger(passenger, translate_to_lang(ugettext_noop("We're sorry, but we have encountered an error while handling your request")
                             , order.language_code)) # use dummy ugettext for makemessages
                log_event(EventType.ORDER_ERROR, order=order, passenger=order.passenger)
                logging.error("book_order: OrderError: %d" % order_id)
                raise # handle exception in decorator 
            except UpdateStatusError:
                logging.error("book_order failed: cannot set order [%d] status to %s" % (order.id, "ERROR"))
示例#21
0
 def save(self, *args, **kwargs):
     """
     Method to read filetype and then save to the database.
     """
     if self.mediafile:
         self.filetype = mimetypes.guess_type(self.mediafile.path)[0] or ugettext_noop('unknown')
     else:
         self.filetype = ugettext_noop('unknown')
     return super(Mediafile, self).save(*args, **kwargs)
示例#22
0
    def post(self, request):
        """POST /api/team/v0/team_membership"""
        field_errors = {}

        if 'username' not in request.DATA:
            field_errors['username'] = build_api_error(ugettext_noop("Username is required."))

        if 'team_id' not in request.DATA:
            field_errors['team_id'] = build_api_error(ugettext_noop("Team id is required."))

        if field_errors:
            return Response({
                'field_errors': field_errors,
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            team = CourseTeam.objects.get(team_id=request.DATA['team_id'])
        except CourseTeam.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        username = request.DATA['username']
        if not has_team_api_access(request.user, team.course_id, access_username=username):
            return Response(status=status.HTTP_404_NOT_FOUND)

        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        course_module = modulestore().get_course(team.course_id)
        if course_module.teams_max_size is not None and team.users.count() >= course_module.teams_max_size:
            return Response(
                build_api_error(ugettext_noop("This team is already full.")),
                status=status.HTTP_400_BAD_REQUEST
            )

        try:
            membership = team.add_user(user)
        except AlreadyOnTeamInCourse:
            return Response(
                build_api_error(
                    ugettext_noop("The user {username} is already a member of a team in this course."),
                    username=username
                ),
                status=status.HTTP_400_BAD_REQUEST
            )
        except NotEnrolledInCourseForTeam:
            return Response(
                build_api_error(
                    ugettext_noop("The user {username} is not enrolled in the course associated with this team."),
                    username=username
                ),
                status=status.HTTP_400_BAD_REQUEST
            )

        serializer = self.get_serializer(instance=membership)
        return Response(serializer.data)
示例#23
0
    def get(self, request):
        """GET /api/team/v0/teams/"""
        result_filter = {"is_active": True}

        if "course_id" in request.QUERY_PARAMS:
            course_id_string = request.QUERY_PARAMS["course_id"]
            try:
                course_key = CourseKey.from_string(course_id_string)
                # Ensure the course exists
                if not modulestore().has_course(course_key):
                    return Response(status=status.HTTP_404_NOT_FOUND)
                result_filter.update({"course_id": course_key})
            except InvalidKeyError:
                error = build_api_error(
                    ugettext_noop("The supplied course id {course_id} is not valid."), course_id=course_id_string
                )
                return Response(error, status=status.HTTP_400_BAD_REQUEST)

            if not has_team_api_access(request.user, course_key):
                return Response(status=status.HTTP_403_FORBIDDEN)
        else:
            return Response(
                build_api_error(ugettext_noop("course_id must be provided")), status=status.HTTP_400_BAD_REQUEST
            )

        if "topic_id" in request.QUERY_PARAMS:
            result_filter.update({"topic_id": request.QUERY_PARAMS["topic_id"]})
        if "include_inactive" in request.QUERY_PARAMS and request.QUERY_PARAMS["include_inactive"].lower() == "true":
            del result_filter["is_active"]
        if "text_search" in request.QUERY_PARAMS:
            return Response(
                build_api_error(ugettext_noop("text_search is not yet supported.")), status=status.HTTP_400_BAD_REQUEST
            )

        queryset = CourseTeam.objects.filter(**result_filter)

        order_by_input = request.QUERY_PARAMS.get("order_by", "name")
        if order_by_input == "name":
            queryset = queryset.extra(select={"lower_name": "lower(name)"})
            order_by_field = "lower_name"
        elif order_by_input == "open_slots":
            queryset = queryset.annotate(team_size=Count("users"))
            order_by_field = "team_size"
        elif order_by_input == "last_activity":
            return Response(
                build_api_error(ugettext_noop("last_activity is not yet supported")), status=status.HTTP_400_BAD_REQUEST
            )

        queryset = queryset.order_by(order_by_field)

        if not queryset:
            return Response(status=status.HTTP_404_NOT_FOUND)

        page = self.paginate_queryset(queryset)
        serializer = self.get_pagination_serializer(page)
        return Response(serializer.data)  # pylint: disable=maybe-no-member
示例#24
0
    def played(self):
        """ Both players have played, save and score
        Notice the fact this is the only function where the scoring is affected
        """
        """ Handle artifacts and spells """
        for u in (self.user_to, self.user_from):
            # always lose, you mofo
            if u.user.has_modifier('challenge-always-lose'):
                u.score = -1
            # affect bonuses
            if u.user.has_modifier('challenge-affect-scoring'):
                u.percents = u.user.modifier_percents('challenge-affect-scoring')
            else:
                u.percents = 100

        if self.user_to.score > self.user_from.score:
            result = (self.user_to, self.user_from)
        elif self.user_from.score > self.user_to.score:
            result = (self.user_from, self.user_to)
        else: #draw game
            result = 'draw'

        if result == 'draw':
            self.status = 'D'
            scoring.score(self.user_to.user, ChallengeGame, 'chall-draw', percents=self.user_to.percents)
            scoring.score(self.user_from.user, ChallengeGame, 'chall-draw', percents=self.user_from.percents)
            # send activty signal
            signal_msg = ugettext_noop('draw result between {user_to} and {user_from}:\n{extra}')
            signals.addActivity.send(sender=None, user_from=self.user_to.user, \
                                     user_to=self.user_from.user, \
                                     message=signal_msg, \
                                     arguments=dict(user_to=self.user_to, user_from=self.user_from,
                                                    extra=self.extraInfo(self.user_from, self.user_to)),\
                                     game=ChallengeGame.get_instance())
        else:
            self.status = 'P'
            self.user_won, self.user_lost = result
            self.winner = self.user_won.user
            diff_race = self.user_won.user.series != self.user_lost.user.series
            diff_class = self.user_won.user.proximate_group != self.user_lost.user.proximate_group
            diff_race = 1 if diff_race else 0
            diff_class = 1 if diff_class else 0
            scoring.score(self.user_won.user, ChallengeGame, 'chall-won',
                external_id=self.id, percents=self.user_won.percents,
                points=self.user_won.score, points2=self.user_lost.score,
                different_race=diff_race, different_class=diff_class)
            scoring.score(self.user_lost.user, ChallengeGame, 'chall-lost',
                external_id=self.id, points=self.user_lost.score, points2=self.user_lost.score)
            # send activty signal
            signal_msg = ugettext_noop('won challenge with {user_lost}: {extra}')
            signals.addActivity.send(sender=None, user_from=self.user_won.user, \
                                     user_to=self.user_lost.user, \
                                     message=signal_msg, arguments=dict(user_lost=self.user_lost,
                                                                        extra=self.extraInfo(self.user_won, self.user_lost)), \
                                     game=ChallengeGame.get_instance())
        self.save()
示例#25
0
 def excluded_modification_fields(cls):
     """
     Returns fields which should not be available in a modification form
     
     By default, it returns :attr:`attributes` less attributes returned by
     :meth:`excluded_modification_fields`
     """
     return [ugettext_noop("name"), ugettext_noop("creator"),
             ugettext_noop("owner"), ugettext_noop("ctime"),
             ugettext_noop("mtime")]
示例#26
0
 def on_clicked_yes(self):
     """
     Activate the version, if the user chooses 'yes'.
     """
     self.object.active_version = self.version
     self.object.save(update_fields=['active_version'])
     self.object.write_log(
         message_list=[ugettext_noop('Version'),
                       ' %d ' % self.version.version_number,
                       ugettext_noop('permitted')],
         person=self.request.user)
示例#27
0
 def removed_from_gig(cls, user, song, old_gig):
     changes = [
         {'title': ugettext_noop('Gig'),
          'title_translatable': True,
          'prev': str(old_gig),
          'new': ''}
     ]
     action = (ugettext_noop('%(who)s (f) removed song from gig %(when)s')
               if user.profile.gender == 'f' else
               ugettext_noop('%(who)s (m) removed song from gig %(when)s'))
     cls._song_changed(song, action, user, changes, override_gig=old_gig)
示例#28
0
    def __init__(self, can_edit_eula, *args, **kwargs):
        super(DomainInternalForm, self).__init__(*args, **kwargs)
        self.can_edit_eula = can_edit_eula
        additional_fields = []
        if self.can_edit_eula:
            additional_fields = ['custom_eula', 'can_use_data']
            self.fields['custom_eula'] = ChoiceField(
                label=ugettext_noop("Custom Eula?"),
                choices=tf_choices(_('Yes'), _('No')),
                required=False,
                help_text='Set to "yes" if this project has a customized EULA as per their contract.'
            )
            self.fields['can_use_data'] = ChoiceField(
                label=ugettext_noop("Can use project data?"),
                choices=tf_choices('Yes', 'No'),
                required=False,
                help_text='Set to "no" if this project opts out of data usage. Defaults to "yes".'
            )

        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.layout = crispy.Layout(
            crispy.Fieldset(
                _("Basic Information"),
                'initiative',
                'workshop_region',
                'self_started',
                'is_test',
                'area',
                'sub_area',
                'organization_name',
                'notes',
                'phone_model',
                'deployment_date',
                'countries',
                'commtrack_domain',
                crispy.Div(*additional_fields),
            ),
            crispy.Fieldset(
                _("Salesforce Details"),
                'sf_contract_id',
                'sf_account_id',
                'services',
            ),
            FormActions(
                StrictButton(
                    _("Update Project Information"),
                    type="submit",
                    css_class='btn btn-primary',
                ),
            ),
        )
示例#29
0
 def excluded_modification_fields(cls):
     """
     Returns fields which should not be available in a modification form
     """
     return [ugettext_noop("type"), ugettext_noop("reference"),
             ugettext_noop("revision"),
             ugettext_noop("ctime"), ugettext_noop("creator"),
             ugettext_noop("owner"), ugettext_noop("ctime"),
             ugettext_noop("mtime"), ugettext_noop("group")]
示例#30
0
    def test_happy_scenario(self):
        value = 'Submit'

        with override_lang('eo'):
            with patch('util.i18n.ugettext') as patched_ugettext:
                result = force_translate(
                    value,
                    ugettext_noop('Submit'),
                    ugettext_noop('Cancel'),
                )

        self.assertNotEqual(value, unicode(result))
        patched_ugettext.assert_called_once_with('Submit')
示例#31
0
class CommTrackSettingsView(BaseCommTrackManageView):
    urlname = 'commtrack_settings'
    page_title = ugettext_noop("Advanced Settings")
    template_name = 'domain/admin/commtrack_settings.html'

    @property
    @memoized
    def commtrack_settings(self):
        return self.domain_object.commtrack_settings

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

    @property
    @memoized
    def commtrack_settings_form(self):
        initial = self.commtrack_settings.to_json()
        initial.update(
            dict(('consumption_' + k, v) for k, v in
                 self.commtrack_settings.consumption_config.to_json().items()))
        initial.update(
            dict(
                ('stock_' + k, v) for k, v in
                self.commtrack_settings.stock_levels_config.to_json().items()))

        if self.request.method == 'POST':
            return CommTrackSettingsForm(self.request.POST,
                                         initial=initial,
                                         domain=self.domain)
        return CommTrackSettingsForm(initial=initial, domain=self.domain)

    def set_ota_restore_config(self):
        """
        If the checkbox for syncing consumption fixtures is
        checked, then we build the restore config with appropriate
        special properties, otherwise just clear the object.

        If there becomes a way to tweak these on the UI, this should
        be done differently.
        """

        if self.commtrack_settings.sync_consumption_fixtures:
            self.domain_object.commtrack_settings.ota_restore_config = StockRestoreConfig(
                section_to_consumption_types={'stock': 'consumption'},
                force_consumption_case_types=[SUPPLY_POINT_CASE_TYPE],
                use_dynamic_product_list=True,
            )
        else:
            self.domain_object.commtrack_settings.ota_restore_config = StockRestoreConfig(
            )

    def post(self, request, *args, **kwargs):
        if self.commtrack_settings_form.is_valid():
            data = self.commtrack_settings_form.cleaned_data
            previous_config = copy.copy(self.commtrack_settings)
            self.commtrack_settings.use_auto_consumption = bool(
                data.get('use_auto_consumption'))
            self.commtrack_settings.sync_consumption_fixtures = bool(
                data.get('sync_consumption_fixtures'))
            self.commtrack_settings.individual_consumption_defaults = bool(
                data.get('individual_consumption_defaults'))

            self.set_ota_restore_config()

            fields = ('emergency_level', 'understock_threshold',
                      'overstock_threshold')
            for field in fields:
                if data.get('stock_' + field):
                    setattr(self.commtrack_settings.stock_levels_config, field,
                            data['stock_' + field])

            consumption_fields = ('min_transactions', 'min_window',
                                  'optimal_window')
            for field in consumption_fields:
                if data.get('consumption_' + field):
                    setattr(self.commtrack_settings.consumption_config, field,
                            data['consumption_' + field])

            self.commtrack_settings.save()

            for loc_type in LocationType.objects.filter(
                    domain=self.domain).all():
                # This will update stock levels based on commtrack config
                loc_type.save()

            if (previous_config.use_auto_consumption !=
                    self.commtrack_settings.use_auto_consumption
                    or previous_config.consumption_config.to_json() !=
                    self.commtrack_settings.consumption_config.to_json()):
                # kick off delayed consumption rebuild
                recalculate_domain_consumption_task.delay(self.domain)
                messages.success(
                    request,
                    _("Settings updated! Your updated consumption settings may take a "
                      "few minutes to show up in reports and on phones."))
            else:
                messages.success(request, _("Settings updated!"))
            return HttpResponseRedirect(self.page_url)
        return self.get(request, *args, **kwargs)
示例#32
0
class DeIdDailySavedExportListView(DailySavedExportListView, DeIdDailySavedExportListHelper):
    urlname = 'list_deid_daily_saved_exports'
    page_title = ugettext_noop("Export De-Identified Daily Saved Exports")
示例#33
0
from django.db import models
from django.contrib.auth.models import User

from django.dispatch import receiver
from django.db.models.signals import post_save
from django.utils.translation import ugettext_noop

from config_models.models import ConfigurationModel
from student.models import CourseEnrollment

from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField, NoneToEmptyManager

FORUM_ROLE_ADMINISTRATOR = ugettext_noop('Administrator')
FORUM_ROLE_MODERATOR = ugettext_noop('Moderator')
FORUM_ROLE_COMMUNITY_TA = ugettext_noop('Community TA')
FORUM_ROLE_STUDENT = ugettext_noop('Student')


@receiver(post_save, sender=CourseEnrollment)
def assign_default_role_on_enrollment(sender, instance, **kwargs):
    """
    Assign forum default role 'Student'
    """
    # The code below would remove all forum Roles from a user when they unenroll
    # from a course. Concerns were raised that it should apply only to students,
    # or that even the history of student roles is important for research
    # purposes. Since this was new functionality being added in this release,
    # I'm just going to comment it out for now and let the forums team deal with
示例#34
0
class DistrictWeekly(BaseReport):
    fields = [
        'corehq.apps.reports.filters.dates.DatespanFilter',
        'custom.reports.mc.reports.fields.DistrictField',
    ]
    slug = 'district_weekly_ucr'
    name = ugettext_noop("mc_report_dist_weekly")
    section = DISTRICT_WEEKLY_REPORT

    @property
    def columns(self):
        return [
            self.first_column,
            DatabaseColumn(_('home_visits_pregnant'),
                           CountColumn('home_visit', alias="home_visits_pregnant",
                                       filters=self.filters + [EQ('home_visit', 'one')])),
            DatabaseColumn(_('home_visits_non_pregnant'),
                           CountColumn('home_visit', alias="home_visits_non_pregnant",
                                       filters=self.filters + [EQ('home_visit', 'zero')])),
            DatabaseColumn(_('home_visits_newborn'),
                           CountColumn('doc_id', alias="home_visits_newborn",
                                       filters=self.filters + [OR([EQ('newborn_reg', 'one'),
                                                                   EQ('newborn_followup', 'one')])])),
            DatabaseColumn(_('home_visits_children'),
                           CountColumn('doc_id', alias="home_visits_children",
                                       filters=self.filters + [OR([EQ('child_reg', 'one'),
                                                                   EQ('child_followup', 'one')])])),
            DatabaseColumn(_('home_visits_followup'),
                           CountColumn('doc_id', alias="home_visits_followup",
                                       filters=self.filters + [OR([
                                           EQ('newborn_followup', 'one'),
                                           EQ('child_followup', 'one'),
                                           EQ('adult_followup', 'one')
                                       ])])),
            AggregateColumn(_("home_visits_total"), add_all, [
                AliasColumn("home_visits_pregnant"),
                AliasColumn("home_visits_non_pregnant"),
                AliasColumn("home_visits_newborn"),
                AliasColumn("home_visits_children"),
                AliasColumn("home_visits_followup"),
            ], slug='home_visits_total'),
            DatabaseColumn(_('deaths_children'),
                           CountColumn('doc_id', alias='deaths_children',
                                       filters=self.filters + [EQ('deaths_children', 'one')])),
            DatabaseColumn(_('patients_given_pneumonia_meds_num'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_pneumonia_meds_num',
                               filters=self.filters + [OR([
                                   AND([EQ('has_pneumonia', 'one'), EQ('it_ari_child', 'one')]),
                                   AND([EQ('pneumonia_ds', 'one'), EQ('it_ari_child', 'one')]),
                                   AND([EQ('ari_adult', 'one'), EQ('it_ari_adult', 'one')])])])),
            DatabaseColumn(_('patients_given_pneumonia_meds_denom'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_pneumonia_meds_denom',
                               filters=self.filters + [OR([
                                   EQ('has_pneumonia', 'one'),
                                   EQ('pneumonia_ds', 'one'),
                                   EQ('ari_adult', 'one')])])),
            AggregateColumn(_('patients_given_pneumonia_meds'), percent_format, [
                AliasColumn('patients_given_pneumonia_meds_num'),
                AliasColumn('patients_given_pneumonia_meds_denom')
            ], slug='patients_given_pneumonia_meds'),
            DatabaseColumn(_('patients_given_diarrhoea_meds_num'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_diarrhoea_meds_num',
                               filters=self.filters + [OR([
                                   AND([OR([EQ('diarrhoea_ds', 'one'), EQ('diarrhoea', 'one')]),
                                        EQ('it_diarrhea_child', 'one')]),
                                   AND([EQ('diarrhea_adult', 'one'), EQ('it_diarrhea_adult', 'one')])])])),
            DatabaseColumn(_('patients_given_diarrhoea_meds_denum'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_diarrhoea_meds_denum',
                               filters=self.filters + [OR([
                                   EQ('diarrhoea_ds', 'one'),
                                   EQ('diarrhoea', 'one'),
                                   EQ('diarrhea_adult', 'one')])])),
            AggregateColumn(_('patients_given_diarrhoea_meds'), percent_format, [
                AliasColumn('patients_given_diarrhoea_meds_num'),
                AliasColumn('patients_given_diarrhoea_meds_denum')
            ], slug='patients_given_diarrhoea_meds'),
            DatabaseColumn(_('patients_given_malaria_meds'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_malaria_meds_num',
                               filters=self.filters + [OR([
                                   AND([EQ('malaria_child', 'one'), EQ('it_malaria_child', 'one')]),
                                   AND([EQ('malaria_adult', 'one'), EQ('it_malaria_adult', 'one')])])])),
            DatabaseColumn(_('patients_given_malaria_meds_denum'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_malaria_meds_demum',
                               filters=self.filters + [OR([
                                   EQ('has_malaria', 'one'),
                                   EQ('malaria_adult', 'one')])])),
            AggregateColumn(_('patients_given_malaria_meds'), percent_format, [
                AliasColumn('patients_given_malaria_meds_num'),
                AliasColumn('patients_given_malaria_meds_demum')
            ], slug='patients_given_malaria_meds'),
            DatabaseColumn(_('patients_correctly_referred_num'),
                           CountColumn(
                               'doc_id',
                               alias='patients_correctly_referred_num',
                               filters=self.filters + [OR([
                                   AND([EQ('referral_needed_newborn', 'one'), EQ('referral_given_newborn', 'one')]),
                                   AND([EQ('referral_needed_child', 'one'), EQ('referral_given_child', 'one')]),
                                   AND([EQ('treatment_preg_ds', 'one'), EQ('referral_given_adult', 'one')])])])),
            DatabaseColumn(_('patients_correctly_referred_denum'),
                           CountColumn(
                               'doc_id',
                               alias='patients_correctly_referred_denum',
                               filters=self.filters + [OR([
                                   EQ('referral_needed_newborn', 'one'),
                                   EQ('referral_needed_child', 'one'),
                                   EQ('treatment_preg_ds', 'one')])])),
            AggregateColumn(_('patients_correctly_referred'), percent_format, [
                AliasColumn('patients_correctly_referred_num'),
                AliasColumn('patients_correctly_referred_denum')
            ], slug='patients_correctly_referred'),
            DatabaseColumn(_('cases_rdt_not_done'),
                           CountColumn('cases_rdt_not_done',
                                       filters=self.filters + [EQ('cases_rdt_not_done', 'one')])),
            DatabaseColumn(_('cases_danger_signs_not_referred'),
                           CountColumn('doc_id', alias='cases_danger_signs_not_referred',
                                       filters=self.filters + [OR([
                                           AND([EQ('internal_newborn_has_danger_sign', 'one'),
                                                EQ('referral_reported_newborn', 'zero')]),
                                           AND([EQ('internal_child_has_danger_sign', 'one'),
                                                EQ('internal_child_referral_not_given', 'one')]),
                                           AND([EQ('treatment_preg_ds', 'one'),
                                                EQ('internal_adult_referral_not_given', 'one')])
                                       ])])),
            DatabaseColumn(_('cases_no_malaria_meds'),
                           CountColumn('doc_id', alias='cases_no_malaria_meds',
                                       filters=self.filters + [OR([
                                           EQ('internal_child_no_malaria_meds', 'one'),
                                           EQ('internal_adult_no_malaria_meds', 'one')
                                       ])]))
        ]
示例#35
0
class LocationTypesView(BaseDomainView):
    urlname = 'location_types'
    page_title = ugettext_noop("Organization Levels")
    template_name = 'locations/location_types.html'
    section_name = ugettext_lazy("Locations")

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

    @method_decorator(can_edit_location_types)
    @use_jquery_ui
    @method_decorator(check_pending_locations_import())
    def dispatch(self, request, *args, **kwargs):
        return super(LocationTypesView, self).dispatch(request, *args,
                                                       **kwargs)

    @property
    def page_context(self):
        return {
            'location_types': self._get_loc_types(),
            'commtrack_enabled': self.domain_object.commtrack_enabled,
        }

    def _get_loc_types(self):
        return [{
            'pk':
            loc_type.pk,
            'name':
            loc_type.name,
            'parent_type':
            (loc_type.parent_type.pk if loc_type.parent_type else None),
            'administrative':
            loc_type.administrative,
            'shares_cases':
            loc_type.shares_cases,
            'view_descendants':
            loc_type.view_descendants,
            'has_user':
            loc_type.has_user,
            'code':
            loc_type.code,
            'expand_from':
            loc_type.expand_from.pk if loc_type.expand_from else None,
            'expand_from_root':
            loc_type.expand_from_root,
            'expand_to':
            loc_type.expand_to_id if loc_type.expand_to_id else None,
            'include_without_expanding':
            (loc_type.include_without_expanding_id
             if loc_type.include_without_expanding_id else None),
        } for loc_type in LocationType.objects.by_domain(self.domain)]

    @method_decorator(lock_locations)
    def post(self, request, *args, **kwargs):
        payload = json.loads(request.POST.get('json'))
        sql_loc_types = {}

        def _is_fake_pk(pk):
            return isinstance(pk, basestring) and pk.startswith("fake-pk-")

        def mk_loctype(name, parent_type, administrative, has_user,
                       shares_cases, view_descendants, pk, code, **kwargs):
            parent = sql_loc_types[parent_type] if parent_type else None

            loc_type = None
            if not _is_fake_pk(pk):
                try:
                    loc_type = LocationType.objects.get(domain=self.domain,
                                                        pk=pk)
                except LocationType.DoesNotExist:
                    pass
            if loc_type is None:
                loc_type = LocationType(domain=self.domain)
            loc_type.name = name
            loc_type.administrative = administrative
            loc_type.parent_type = parent
            loc_type.shares_cases = shares_cases
            loc_type.view_descendants = view_descendants
            loc_type.code = unicode_slug(code)
            loc_type.has_user = has_user
            sql_loc_types[pk] = loc_type
            loc_type.save()

        loc_types = payload['loc_types']
        pks = []
        for loc_type in loc_types:
            for prop in [
                    'name', 'parent_type', 'administrative', 'shares_cases',
                    'view_descendants', 'pk'
            ]:
                if prop not in loc_type:
                    raise LocationConsistencyError(
                        "Missing an organization level property!")
            pk = loc_type['pk']
            if not _is_fake_pk(pk):
                pks.append(loc_type['pk'])

        names = [lt['name'] for lt in loc_types]
        names_are_unique = len(names) == len(set(names))
        codes = [lt['code'] for lt in loc_types if lt['code']]
        codes_are_unique = len(codes) == len(set(codes))
        if not names_are_unique or not codes_are_unique:
            raise LocationConsistencyError(
                "'name' and 'code' are supposed to be unique")

        hierarchy = self.get_hierarchy(loc_types)

        if not self.remove_old_location_types(pks):
            return self.get(request, *args, **kwargs)

        for loc_type in hierarchy:
            # make all locations in order
            mk_loctype(**loc_type)

        for loc_type in hierarchy:
            # apply sync boundaries (expand_from, expand_to and include_without_expanding) after the
            # locations are all created since there are dependencies between them
            self._attach_sync_boundaries_to_location_type(
                loc_type, sql_loc_types)

        return HttpResponseRedirect(reverse(self.urlname, args=[self.domain]))

    @staticmethod
    def _attach_sync_boundaries_to_location_type(loc_type_data, loc_type_db):
        """Store the sync expansion boundaries along with the location type. i.e. where
        the user's locations start expanding from, and where they expand to

        """
        loc_type = loc_type_db[loc_type_data['pk']]
        expand_from_id = loc_type_data['expand_from']
        expand_to_id = loc_type_data['expand_to']
        include_without_expanding_id = loc_type_data[
            'include_without_expanding']
        try:
            loc_type.expand_from = loc_type_db[
                expand_from_id] if expand_from_id else None
        except KeyError:  # expand_from location type was deleted
            loc_type.expand_from = None
        loc_type.expand_from_root = loc_type_data['expand_from_root']
        try:
            loc_type.expand_to = loc_type_db[
                expand_to_id] if expand_to_id else None
        except KeyError:  # expand_to location type was deleted
            loc_type.expand_to = None
        try:
            loc_type.include_without_expanding = (
                loc_type_db[include_without_expanding_id]
                if include_without_expanding_id else None)
        except KeyError:  # include_without_expanding location type was deleted
            loc_type.include_without_expanding = None
        loc_type.save()

    def remove_old_location_types(self, pks):
        existing_pks = (LocationType.objects.filter(
            domain=self.domain).values_list('pk', flat=True))
        to_delete = []
        for pk in existing_pks:
            if pk not in pks:
                if (SQLLocation.objects.filter(domain=self.domain,
                                               location_type=pk).exists()):
                    msg = _(
                        "You cannot delete organization levels that have locations"
                    )
                    messages.warning(self.request, msg)
                    return False
                to_delete.append(pk)
        (LocationType.objects.filter(domain=self.domain,
                                     pk__in=to_delete).delete())
        return True

    # This is largely copy-pasted from the LocationTypeManager
    def get_hierarchy(self, loc_types):
        """
        Return loc types in order from parents to children
        """
        assert_no_cycles([(lt['pk'],
                           lt['parent_type']) if lt['parent_type'] else
                          (lt['pk'], ROOT_LOCATION_TYPE) for lt in loc_types])

        lt_dict = {lt['pk']: lt for lt in loc_types}
        hierarchy = {}

        def insert_loc_type(loc_type):
            """
            Get parent location's hierarchy, insert loc_type into it,
            and return hierarchy below loc_type
            """
            name = loc_type['name']
            parent = lt_dict.get(loc_type['parent_type'], None)
            if not parent:
                lt_hierarchy = hierarchy
            else:
                lt_hierarchy = insert_loc_type(parent)
            if name not in lt_hierarchy:
                lt_hierarchy[name] = (loc_type, {})
            return lt_hierarchy[name][1]

        for loc_type in loc_types:
            insert_loc_type(loc_type)

        ordered_loc_types = []

        def step_through_graph(hierarchy):
            for name, (loc_type, children) in hierarchy.items():
                ordered_loc_types.append(loc_type)
                step_through_graph(children)

        step_through_graph(hierarchy)
        return ordered_loc_types
示例#36
0
class ReportingRatesReport(GenericTabularReport, CommtrackReportMixin):
    name = ugettext_noop('Reporting Rate')
    slug = 'reporting_rate'
    fields = [
        'corehq.apps.reports.filters.fixtures.AsyncLocationFilter',
        'corehq.apps.reports.filters.forms.FormsByApplicationFilter',
        'corehq.apps.reports.filters.dates.DatespanFilter',
        'corehq.apps.reports.filters.commtrack.SelectReportingType',
    ]
    exportable = True
    emailable = True

    @classmethod
    def display_in_dropdown(cls, domain=None, project=None, user=None):
        return True

    def is_aggregate_report(self):
        return self.request.GET.get(SelectReportingType.slug,
                                    '') != 'facilities'

    @property
    def headers(self):
        if self.is_aggregate_report():
            return DataTablesHeader(*(DataTablesColumn(text) for text in [
                _('Location'),
                _('# Sites'),
                _('# Reporting'),
                _('Reporting Rate'),
                _('# Non-reporting'),
                _('Non-reporting Rate'),
            ]))
        else:
            return DataTablesHeader(*(DataTablesColumn(text) for text in [
                _('Location'),
                _('Parent location'),
                _('Date of last report for selected period'),
                _('Reporting'),
            ]))

    @property
    @memoized
    def _facility_data(self):
        config = {
            'domain': self.domain,
            'location_id': self.request.GET.get('location_id'),
            'startdate': self.datespan.startdate_utc,
            'enddate': self.datespan.enddate_utc,
            'request': self.request,
        }
        statuses = list(ReportingStatusDataSource(config).get_data())

        results = []
        for status in statuses:
            results.append([
                status['name'],
                status['parent_name'],
                status['last_reporting_date'].date()
                if status['last_reporting_date'] else _('Never'),
                _('Yes')
                if status['reporting_status'] == 'reporting' else _('No'),
            ])

        master_tally = self.status_tally(
            [site['reporting_status'] for site in statuses])

        return master_tally, results

    @property
    @memoized
    def _aggregate_data(self):
        config = {
            'domain': self.domain,
            'location_id': self.request.GET.get('location_id'),
            'startdate': self.datespan.startdate_utc,
            'enddate': self.datespan.enddate_utc,
            'request': self.request,
        }
        statuses = list(ReportingStatusDataSource(config).get_data())

        def child_loc(path):
            root = self.active_location
            ix = path.index(root.location_id) if root else -1
            try:
                return path[ix + 1]
            except IndexError:
                return None

        def case_iter():
            for site in statuses:
                if child_loc(site['loc_path']) is not None:
                    yield (site['loc_path'], site['reporting_status'])

        status_by_agg_site = map_reduce(
            lambda path_status: [(child_loc(path_status[0]), path_status[1])],
            data=case_iter())
        sites_by_agg_site = map_reduce(lambda path_status1: [(child_loc(
            path_status1[0]), path_status1[0][-1])],
                                       data=case_iter())

        status_counts = dict(
            (loc_id, self.status_tally(statuses))
            for loc_id, statuses in status_by_agg_site.items())

        master_tally = self.status_tally(
            [site['reporting_status'] for site in statuses])

        locs = (SQLLocation.objects.filter(
            is_archived=False,
            location_id__in=list(status_counts)).order_by('name'))

        def fmt(pct):
            return '%.1f%%' % (100. * pct)

        def fmt_pct_col(loc_id, col_type):
            return fmt(status_counts[loc_id].get(col_type, {'pct': 0.})['pct'])

        def fmt_count_col(loc_id, col_type):
            return status_counts[loc_id].get(col_type, {'count': 0})['count']

        def _rows():
            for loc in locs:
                row = [loc.name, len(sites_by_agg_site[loc.location_id])]
                for k in ('reporting', 'nonreporting'):
                    row.append(fmt_count_col(loc.location_id, k))
                    row.append(fmt_pct_col(loc.location_id, k))

                yield row

        return master_tally, _rows()

    def status_tally(self, statuses):
        total = len(statuses)

        return map_reduce(lambda s: [(s, )],
                          lambda v: {
                              'count': len(v),
                              'pct': len(v) / float(total)
                          },
                          data=statuses)

    @property
    def rows(self):
        if self.is_aggregate_report():
            return self._aggregate_data[1]
        else:
            return self._facility_data[1]

    def master_pie_chart_data(self):
        if self.is_aggregate_report():
            tally = self._aggregate_data[0]
        else:
            tally = self._facility_data[0]

        labels = {
            'reporting': _('Reporting'),
            'nonreporting': _('Non-reporting'),
        }
        return [{
            'label': labels[k],
            'value': tally.get(k, {'count': 0.})['count']
        } for k in ('reporting', 'nonreporting')]

    @property
    def charts(self):
        if 'location_id' in self.request.GET:  # hack: only get data if we're loading an actual report
            chart = PieChart(_('Current Reporting'), 'current_reporting', [])
            chart.data = self.master_pie_chart_data()
            return [chart]
示例#37
0
class HealthFacilityWeekly(DistrictWeekly):
    report_template_path = "mc/reports/hf_weekly.html"
    extra_context_providers = [hf_message_content]
    fields = [
        'corehq.apps.reports.filters.dates.DatespanFilter',
        'custom.reports.mc.reports.fields.HealthFacilityField',
    ]
    slug = 'hf_weekly_ucr'
    name = ugettext_noop("mc_report_hf_weekly")
    section = HF_WEEKLY_REPORT

    @property
    def columns(self):
        return [
            self.first_column,
            DatabaseColumn(_('home_visits_newborn'),
                           CountColumn('doc_id', alias="home_visits_newborn",
                                       filters=self.filters + [OR([EQ('newborn_reg', 'one'),
                                                                   EQ('newborn_followup', 'one')])])),
            DatabaseColumn(_('home_visits_children'),
                           CountColumn('doc_id', alias="home_visits_children",
                                       filters=self.filters + [OR([EQ('child_reg', 'one'),
                                                                   EQ('child_followup', 'one')])])),
            DatabaseColumn(_('home_visits_adult'),
                           CountColumn('doc_id', alias="home_visits_adult",
                                       filters=self.filters + [NOTEQ('home_visit', 'not')])),
            AggregateColumn(_("home_visits_total"), add_all, [
                AliasColumn("home_visits_newborn"),
                AliasColumn("home_visits_children"),
                AliasColumn("home_visits_adult"),
            ], slug='home_visits_total'),
            DatabaseColumn(_('cases_transferred'),
                           CountColumn('doc_id', alias='cases_transferred',
                                       filters=self.filters + [OR([
                                           EQ('referral_reported_newborn', 'one'),
                                           EQ('referral_given_child', 'one'),
                                           EQ('referral_given_adult', 'one'),
                                       ])])),
            DatabaseColumn(_('home_visits_followup'),
                           CountColumn('doc_id', alias="home_visits_followup",
                                       filters=self.filters + [OR([
                                           EQ('newborn_followup', 'one'),
                                           EQ('child_followup', 'one'),
                                           EQ('adult_followup', 'one')
                                       ])])),
            DatabaseColumn(_('patients_given_pneumonia_meds_num'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_pneumonia_meds_num',
                               filters=self.filters + [OR([
                                   AND([EQ('has_pneumonia', 'one'), EQ('it_ari_child', 'one')]),
                                   AND([EQ('pneumonia_ds', 'one'), EQ('it_ari_child', 'one')]),
                                   AND([EQ('ari_adult', 'one'), EQ('it_ari_adult', 'one')])])])),
            DatabaseColumn(_('patients_given_pneumonia_meds_denom'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_pneumonia_meds_denom',
                               filters=self.filters + [OR([
                                   EQ('has_pneumonia', 'one'),
                                   EQ('pneumonia_ds', 'one'),
                                   EQ('ari_adult', 'one')])])),
            AggregateColumn(_('patients_given_pneumonia_meds'), percent_format, [
                AliasColumn('patients_given_pneumonia_meds_num'),
                AliasColumn('patients_given_pneumonia_meds_denom')
            ], slug='patients_given_pneumonia_meds'),
            DatabaseColumn(_('patients_given_diarrhoea_meds_num'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_diarrhoea_meds_num',
                               filters=self.filters + [OR([
                                   AND([OR([EQ('diarrhoea_ds', 'one'), EQ('diarrhoea', 'one')]),
                                        EQ('it_diarrhea_child', 'one')]),
                                   AND([EQ('diarrhea_adult', 'one'), EQ('it_diarrhea_adult', 'one')])])])),
            DatabaseColumn(_('patients_given_diarrhoea_meds_denum'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_diarrhoea_meds_denum',
                               filters=self.filters + [OR([
                                   EQ('diarrhoea_ds', 'one'),
                                   EQ('diarrhoea', 'one'),
                                   EQ('diarrhea_adult', 'one')])])),
            AggregateColumn(_('patients_given_diarrhoea_meds'), percent_format, [
                AliasColumn('patients_given_diarrhoea_meds_num'),
                AliasColumn('patients_given_diarrhoea_meds_denum')
            ], slug='patients_given_diarrhoea_meds'),
            DatabaseColumn(_('patients_given_malaria_meds'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_malaria_meds_num',
                               filters=self.filters + [OR([
                                   AND([EQ('malaria_child', 'one'), EQ('it_malaria_child', 'one')]),
                                   AND([EQ('malaria_adult', 'one'), EQ('it_malaria_adult', 'one')])])])),
            DatabaseColumn(_('patients_given_malaria_meds_denum'),
                           CountColumn(
                               'doc_id',
                               alias='patients_given_malaria_meds_demum',
                               filters=self.filters + [OR([
                                   EQ('has_malaria', 'one'),
                                   EQ('malaria_adult', 'one')])])),
            AggregateColumn(_('patients_given_malaria_meds'), percent_format, [
                AliasColumn('patients_given_malaria_meds_num'),
                AliasColumn('patients_given_malaria_meds_denum')
            ], slug='patients_given_malaria_meds'),
            DatabaseColumn(_('patients_correctly_referred_num'),
                           CountColumn(
                               'doc_id',
                               alias='patients_correctly_referred_num',
                               filters=self.filters + [OR([
                                   AND([EQ('referral_needed_newborn', 'one'), EQ('referral_given_newborn', 'one')]),
                                   AND([EQ('referral_needed_child', 'one'), EQ('referral_given_child', 'one')]),
                                   AND([EQ('treatment_preg_ds', 'one'), EQ('referral_given_adult', 'one')])])])),
            DatabaseColumn(_('patients_correctly_referred_denum'),
                           CountColumn(
                               'doc_id',
                               alias='patients_correctly_referred_denum',
                               filters=self.filters + [OR([
                                   EQ('referral_needed_newborn', 'one'),
                                   EQ('referral_needed_child', 'one'),
                                   EQ('treatment_preg_ds', 'one')])])),
            AggregateColumn(_('patients_correctly_referred'), percent_format, [
                AliasColumn('patients_correctly_referred_num'),
                AliasColumn('patients_correctly_referred_denum')
            ], slug='patients_correctly_referred'),
            DatabaseColumn(_('cases_rdt_not_done'),
                           CountColumn('cases_rdt_not_done',
                                       filters=self.filters + [EQ('cases_rdt_not_done', 'one')])),
        ]
示例#38
0
from pretix.base.signals import register_payment_providers
from django.dispatch import receiver
from pretix.base.settings import settings_hierarkey
from django.utils.translation import ugettext_lazy as _, ugettext_noop
from i18nfield.strings import LazyI18nString

@receiver(register_payment_providers, dispatch_uid="payment_cash")
def register_payment_provider(sender, **kwargs):
    from .payment import CashPayment
    return CashPayment

settings_hierarkey.add_default('payment_cashpayment_information_text', LazyI18nString.from_gettext(ugettext_noop(
    "You can pay your order by cash at the venue."
)), LazyI18nString)
示例#39
0
def create_builtin_workflows(sender, **kwargs):
    """
    Creates a simple and a complex workflow.
    """
    workflow_1, created = Workflow.objects.get_or_create(
        name=ugettext_noop('Simple Workflow'))
    if created:
        state_1_1 = State.objects.create(name=ugettext_noop('submitted'),
                                         workflow=workflow_1,
                                         allow_create_poll=True,
                                         allow_support=True,
                                         allow_submitter_edit=True)
        state_1_2 = State.objects.create(name=ugettext_noop('accepted'),
                                         workflow=workflow_1,
                                         action_word=ugettext_noop('Accept'))
        state_1_3 = State.objects.create(name=ugettext_noop('rejected'),
                                         workflow=workflow_1,
                                         action_word=ugettext_noop('Reject'))
        state_1_4 = State.objects.create(
            name=ugettext_noop('not decided'),
            workflow=workflow_1,
            action_word=ugettext_noop('Do not decide'))
        state_1_1.next_states.add(state_1_2, state_1_3, state_1_4)
        workflow_1.first_state = state_1_1
        workflow_1.save()

    workflow_2, created = Workflow.objects.get_or_create(
        name=ugettext_noop('Complex Workflow'))
    if created:
        state_2_1 = State.objects.create(name=ugettext_noop('published'),
                                         workflow=workflow_2,
                                         allow_support=True,
                                         allow_submitter_edit=True,
                                         dont_set_identifier=True)
        state_2_2 = State.objects.create(name=ugettext_noop('permitted'),
                                         workflow=workflow_2,
                                         action_word=ugettext_noop('Permit'),
                                         allow_create_poll=True,
                                         allow_submitter_edit=True,
                                         versioning=True,
                                         leave_old_version_active=True)
        state_2_3 = State.objects.create(name=ugettext_noop('accepted'),
                                         workflow=workflow_2,
                                         action_word=ugettext_noop('Accept'),
                                         versioning=True)
        state_2_4 = State.objects.create(name=ugettext_noop('rejected'),
                                         workflow=workflow_2,
                                         action_word=ugettext_noop('Reject'),
                                         versioning=True)
        state_2_5 = State.objects.create(name=ugettext_noop('withdrawed'),
                                         workflow=workflow_2,
                                         action_word=ugettext_noop('Withdraw'),
                                         versioning=True)
        state_2_6 = State.objects.create(name=ugettext_noop('adjourned'),
                                         workflow=workflow_2,
                                         action_word=ugettext_noop('Adjourn'),
                                         versioning=True)
        state_2_7 = State.objects.create(
            name=ugettext_noop('not concerned'),
            workflow=workflow_2,
            action_word=ugettext_noop('Do not concern'),
            versioning=True)
        state_2_8 = State.objects.create(
            name=ugettext_noop('commited a bill'),
            workflow=workflow_2,
            action_word=ugettext_noop('Commit a bill'),
            versioning=True)
        state_2_9 = State.objects.create(
            name=ugettext_noop('needs review'),
            workflow=workflow_2,
            action_word=ugettext_noop('Needs review'),
            versioning=True)
        state_2_10 = State.objects.create(
            name=ugettext_noop('rejected (not authorized)'),
            workflow=workflow_2,
            action_word=ugettext_noop('Reject (not authorized)'),
            versioning=True)
        state_2_1.next_states.add(state_2_2, state_2_5, state_2_10)
        state_2_2.next_states.add(state_2_3, state_2_4, state_2_5, state_2_6,
                                  state_2_7, state_2_8, state_2_9)
        workflow_2.first_state = state_2_1
        workflow_2.save()
示例#40
0
class AddNormalKeywordView(AddStructuredKeywordView):
    urlname = 'add_normal_keyword'
    page_title = ugettext_noop("New Keyword")
    process_structured_message = False
示例#41
0
class UploadCommCareUsers(BaseManageCommCareUserView):
    template_name = 'hqwebapp/bulk_upload.html'
    urlname = 'upload_commcare_users'
    page_title = ugettext_noop("Bulk Upload Mobile Workers")

    @method_decorator(
        requires_privilege_with_fallback(privileges.BULK_USER_MANAGEMENT))
    def dispatch(self, request, *args, **kwargs):
        return super(UploadCommCareUsers,
                     self).dispatch(request, *args, **kwargs)

    @property
    def page_context(self):
        request_params = self.request.GET if self.request.method == 'GET' else self.request.POST
        context = {
            'bulk_upload': {
                "help_site": {
                    "address": BULK_MOBILE_HELP_SITE,
                    "name": _("CommCare Help Site"),
                },
                "download_url":
                reverse("download_commcare_users", args=(self.domain, )),
                "adjective":
                _("mobile worker"),
                "plural_noun":
                _("mobile workers"),
            },
            'show_secret_settings': request_params.get("secret", False),
        }
        context.update({
            'bulk_upload_form': get_bulk_upload_form(context),
        })
        return context

    def post(self, request, *args, **kwargs):
        """View's dispatch method automatically calls this"""
        try:
            self.workbook = get_workbook(request.FILES.get('bulk_upload_file'))
        except WorkbookJSONError as e:
            messages.error(request, str(e))
            return self.get(request, *args, **kwargs)

        try:
            self.user_specs = self.workbook.get_worksheet(title='users')
        except WorksheetNotFound:
            try:
                self.user_specs = self.workbook.get_worksheet()
            except WorksheetNotFound:
                return HttpResponseBadRequest("Workbook has no worksheets")

        try:
            self.group_specs = self.workbook.get_worksheet(title='groups')
        except WorksheetNotFound:
            self.group_specs = []

        try:
            check_headers(self.user_specs)
        except UserUploadError as e:
            messages.error(request, _(str(e)))
            return HttpResponseRedirect(
                reverse(UploadCommCareUsers.urlname, args=[self.domain]))

        task_ref = expose_cached_download(payload=None,
                                          expiry=1 * 60 * 60,
                                          file_extension=None)
        task = import_users_and_groups.delay(
            self.domain,
            list(self.user_specs),
            list(self.group_specs),
        )
        task_ref.set_task(task)
        return HttpResponseRedirect(
            reverse(UserUploadStatusView.urlname,
                    args=[self.domain, task_ref.download_id]))
示例#42
0
class LocationImportView(BaseLocationView):
    urlname = 'location_import'
    page_title = ugettext_noop('Upload Organization Structure From Excel')
    template_name = 'locations/manage/import.html'

    @method_decorator(can_edit_any_location)
    @method_decorator(check_pending_locations_import(redirect=True))
    def dispatch(self, request, *args, **kwargs):
        return super(LocationImportView,
                     self).dispatch(request, *args, **kwargs)

    @property
    def page_context(self):
        def _get_manage_consumption():
            if self.domain_object.commtrack_settings:
                return self.domain_object.commtrack_settings.individual_consumption_defaults
            else:
                return False

        context = {
            'bulk_upload': {
                "download_url": reverse("location_export",
                                        args=(self.domain, )),
                "adjective": _("Organization Structure"),
                "plural_noun": _("Organization Structure"),
            },
            "manage_consumption": _get_manage_consumption(),
        }
        context.update({
            'bulk_upload_form': get_bulk_upload_form(context),
        })
        return context

    @method_decorator(lock_locations)
    def post(self, request, *args, **kwargs):
        upload = request.FILES.get('bulk_upload_file')
        if not upload:
            messages.error(request, _('no file uploaded'))
            return self.get(request, *args, **kwargs)
        if not args:
            messages.error(request, _('no domain specified'))
            return self.get(request, *args, **kwargs)
        if upload.content_type != 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
            messages.error(
                request,
                _("Invalid file-format. Please upload a valid xlsx file."))
            return self.get(request, *args, **kwargs)

        domain = args[0]

        # stash this in soil to make it easier to pass to celery
        TEN_HOURS = 10 * 60 * 60
        file_ref = expose_cached_download(
            upload.read(),
            expiry=TEN_HOURS,
            file_extension=file_extention_from_filename(upload.name),
        )
        # We need to start this task after this current request finishes because this
        # request uses the lock_locations decorator which acquires the same lock that
        # the task will try to acquire.
        task = import_locations_async.apply_async(
            args=[domain, file_ref.download_id], countdown=10)
        # put the file_ref.download_id in cache to lookup from elsewhere
        cache.set(import_locations_task_key(domain), file_ref.download_id,
                  TEN_HOURS)
        file_ref.set_task(task)
        return HttpResponseRedirect(
            reverse(LocationImportStatusView.urlname,
                    args=[domain, file_ref.download_id]))
示例#43
0
class EditLocationView(NewLocationView):
    urlname = 'edit_location'
    page_title = ugettext_noop("Edit Location")
    creates_new_location = False

    @method_decorator(can_edit_location)
    def dispatch(self, request, *args, **kwargs):
        return super(EditLocationView, self).dispatch(request, *args, **kwargs)

    @property
    def location_id(self):
        return self.kwargs['loc_id']

    @property
    @memoized
    def location(self):
        return get_object_or_404(SQLLocation,
                                 domain=self.domain,
                                 location_id=self.location_id)

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

    @property
    def consumption(self):
        consumptions = []
        for product in Product.by_domain(self.domain):
            consumption = get_default_monthly_consumption(
                self.domain,
                product._id,
                self.location.location_type_name,
                self.location.supply_point_id or None,
            )
            if consumption:
                consumptions.append((product.name, consumption))
        return consumptions

    @property
    @memoized
    def products_form(self):
        if (self.location.location_type_object.administrative
                or not toggles.PRODUCTS_PER_LOCATION.enabled(
                    self.request.domain)):
            return None

        form = MultipleSelectionForm(
            initial={'selected_ids': self.products_at_location},
            submit_label=_("Update Product List"),
            fieldset_title=_("Specify Products Per Location"),
            prefix="products",
        )
        form.fields['selected_ids'].choices = self.active_products
        form.fields['selected_ids'].label = _("Products at Location")
        return form

    @property
    @memoized
    def users_form(self):
        if (not self.request.couch_user.can_edit_commcare_users()
                or not self.can_access_all_locations):
            return None
        form = UsersAtLocationForm(
            domain_object=self.domain_object,
            location=self.location,
            data=self.request.POST if self.request.method == "POST" else None,
            submit_label=_("Update Location Membership"),
            fieldset_title=_("Specify Workers at this Location"),
            prefix="users",
        )
        form.fields['selected_ids'].label = _("Workers at Location")
        return form

    @property
    def active_products(self):
        return [(p.product_id, p.name)
                for p in SQLProduct.objects.filter(domain=self.domain,
                                                   is_archived=False).all()]

    @property
    def products_at_location(self):
        return [p.product_id for p in self.location.products.all()]

    @property
    def page_name(self):
        return mark_safe(
            _("Edit {name} <small>{type}</small>").format(
                name=self.location.name,
                type=self.location.location_type_name))

    @property
    def page_context(self):
        context = super(EditLocationView, self).page_context
        context.update({
            'products_per_location_form': self.products_form,
            'users_per_location_form': self.users_form,
        })
        return context

    def users_form_post(self, request, *args, **kwargs):
        if self.users_form and self.users_form.is_valid():
            self.users_form.save()
            return self.form_valid()
        else:
            self.request.method = "GET"
            self.form_tab = 'users'
            return self.get(request, *args, **kwargs)

    def products_form_post(self, request, *args, **kwargs):
        products = SQLProduct.objects.filter(
            product_id__in=request.POST.getlist('products-selected_ids', []))
        self.location.products = products
        self.location.save()
        return self.form_valid()

    @method_decorator(lock_locations)
    def post(self, request, *args, **kwargs):
        if self.request.POST['form_type'] == "location-settings":
            return self.settings_form_post(request, *args, **kwargs)
        elif self.request.POST['form_type'] == "location-users":
            return self.users_form_post(request, *args, **kwargs)
        elif (self.request.POST['form_type'] == "location-products"
              and toggles.PRODUCTS_PER_LOCATION.enabled(request.domain)):
            return self.products_form_post(request, *args, **kwargs)
        else:
            raise Http404()
示例#44
0
class NewLocationView(BaseLocationView):
    urlname = 'create_location'
    page_title = ugettext_noop("New Location")
    template_name = 'locations/manage/location.html'
    creates_new_location = True
    form_tab = 'basic'

    @use_multiselect
    @method_decorator(check_pending_locations_import(redirect=True))
    def dispatch(self, request, *args, **kwargs):
        return super(NewLocationView, self).dispatch(request, *args, **kwargs)

    @property
    def parent_pages(self):
        selected = self.location.location_id or self.location.parent_location_id
        breadcrumbs = [{
            'title':
            LocationsListView.page_title,
            'url':
            reverse(
                LocationsListView.urlname,
                args=[self.domain],
                params={"selected": selected} if selected else None,
            )
        }]
        if self.location.parent:
            sql_parent = self.location.parent
            for loc in sql_parent.get_ancestors(include_self=True):
                breadcrumbs.append({
                    'title':
                    loc.name,
                    'url':
                    reverse(
                        EditLocationView.urlname,
                        args=[self.domain, loc.location_id],
                    )
                })
        return breadcrumbs

    @property
    @memoized
    def location(self):
        parent_id = self.request.GET.get('parent')
        parent = (get_object_or_404(
            SQLLocation, domain=self.domain, location_id=parent_id)
                  if parent_id else None)
        return SQLLocation(domain=self.domain, parent=parent)

    @property
    def consumption(self):
        return None

    @property
    @memoized
    def location_form(self):
        data = self.request.POST if self.request.method == 'POST' else None
        form_set = (ENikshayLocationFormSet if toggles.ENIKSHAY.enabled(
            self.domain) else LocationFormSet)
        return form_set(
            self.location,
            bound_data=data,
            request_user=self.request.couch_user,
            is_new=self.creates_new_location,
        )

    @property
    def page_context(self):
        return {
            'form':
            self.location_form,
            'location':
            self.location,
            'consumption':
            self.consumption,
            'locations':
            load_locs_json(self.domain,
                           self.location.parent_location_id,
                           user=self.request.couch_user),
            'form_tab':
            self.form_tab,
            'creates_new_location':
            self.creates_new_location,
            'loc_types_with_users':
            self._get_loc_types_with_users(),
        }

    def _get_loc_types_with_users(self):
        return list(
            LocationType.objects.filter(domain=self.domain,
                                        has_user=True).values_list('name',
                                                                   flat=True))

    def form_valid(self):
        messages.success(self.request, _('Location saved!'))
        return HttpResponseRedirect(
            reverse(
                EditLocationView.urlname,
                args=[self.domain, self.location_form.location.location_id]), )

    def settings_form_post(self, request, *args, **kwargs):
        if self.location_form.is_valid():
            self.location_form.save()
            return self.form_valid()
        return self.get(request, *args, **kwargs)

    @method_decorator(lock_locations)
    def post(self, request, *args, **kwargs):
        return self.settings_form_post(request, *args, **kwargs)
示例#45
0
class RebuildStockStateView(BaseCommTrackManageView):
    urlname = 'rebuild_stock_state'
    page_title = ugettext_noop("Rebuild Stock State")
    template_name = 'commtrack/manage/rebuild_stock_state.html'

    @memoized
    def get_server_date_by_form_id(self, form_id):
        try:
            server_date = FormAccessors(
                self.domain).get_form(form_id).received_on
        except XFormNotFound:
            return None
        else:
            return ServerTime(server_date).ui_string()

    def _get_selected_case_id(self):
        location_id = self.request.GET.get('location_id')
        if location_id:
            try:
                return (SQLLocation.objects.get(
                    domain=self.domain,
                    location_id=location_id).supply_point_id)
            except SQLLocation.DoesNotExist:
                messages.error(self.request,
                               'Your location id did not match a location')

    @property
    def page_context(self, **kwargs):
        stock_state_limit = int(self.request.GET.get('stock_state_limit', 100))
        stock_transaction_limit = int(
            self.request.GET.get('stock_transaction_limit', 1000))
        stock_state_limit_exceeded = False
        stock_transaction_limit_exceeded = False

        query = StockTransaction.objects.filter(report__domain=self.domain)
        selected_case_id = self._get_selected_case_id()
        if selected_case_id:
            query = query.filter(case_id=selected_case_id)
        selected_product_id = self.request.GET.get('product_id')
        if selected_product_id:
            query = query.filter(product_id=selected_product_id)

        stock_state_keys = [
            (txn.case_id, txn.section_id, txn.product_id)
            for txn in query.order_by('case_id', 'section_id', 'product_id').
            distinct('case_id', 'section_id', 'product_id')[:stock_state_limit]
        ]
        if len(stock_state_keys) >= stock_state_limit:
            stock_state_limit_exceeded = True

        actions_by_stock_state_key = []
        stock_transaction_count = 0
        for stock_state_key in stock_state_keys:
            actions = self.get_actions_by_stock_state_key(*stock_state_key)
            stock_transaction_count += len(actions[1])
            if stock_transaction_count > stock_transaction_limit:
                stock_transaction_limit_exceeded = True
                break
            actions_by_stock_state_key.append(actions)

        assert len(set(stock_state_keys)) == len(stock_state_keys)
        return {
            'actions_by_stock_state_key': actions_by_stock_state_key,
            'stock_state_limit_exceeded': stock_state_limit_exceeded,
            'stock_state_limit': stock_state_limit,
            'stock_transaction_limit_exceeded':
            stock_transaction_limit_exceeded,
            'stock_transaction_limit': stock_transaction_limit,
        }

    def get_actions_by_stock_state_key(self, case_id, section_id, product_id):
        actions = [(
            action.__class__.__name__,
            action,
            self.get_server_date_by_form_id(
                action.stock_transaction.report.form_id),
        )
                   for action in plan_rebuild_stock_state(
                       case_id, section_id, product_id)]
        return ({
            'case_id': case_id,
            'section_id': section_id,
            'product_id': product_id
        }, actions, get_doc_info_by_id(self.domain, case_id))

    def post(self, request, *args, **kwargs):
        case_id = request.POST.get('case_id')
        section_id = request.POST.get('section_id')
        product_id = request.POST.get('product_id')
        if None in (case_id, section_id, product_id):
            return HttpResponseBadRequest()
        rebuild_stock_state(case_id, section_id, product_id)
        return HttpResponseRedirect('.')
示例#46
0
class DeIdDashboardFeedListView(DashboardFeedListView, DeIdDashboardFeedListHelper):
    urlname = 'list_deid_dashboard_feeds'
    page_title = ugettext_noop("Export De-Identified Dashboard Feeds")
示例#47
0
class CurrentStockStatusReport(GenericTabularReport, CommtrackReportMixin):
    name = ugettext_noop('Stock Status by Product')
    slug = 'current_stock_status'
    fields = [
        'corehq.apps.reports.filters.fixtures.AsyncLocationFilter',
        'corehq.apps.reports.filters.commtrack.ProgramFilter',
    ]
    exportable = True
    exportable_all = True
    emailable = True
    asynchronous = True
    ajax_pagination = True

    @property
    def shared_pagination_GET_params(self):
        return [
            {
                'name': 'location_id',
                'value': self.request.GET.get('location_id')
            },
            {
                'name': 'program',
                'value': self.request.GET.get('program')
            },
        ]

    @cached_property
    def _sp_ids(self):
        return get_relevant_supply_point_ids(self.domain, self.active_location)

    @cached_property
    def _program_product_ids(self):
        if self.program_id:
            return get_product_ids_for_program(self.domain, self.program_id)

    @cached_property
    def _product_name_mapping(self):
        return get_product_id_name_mapping(self.domain, self.program_id)

    @cached_property
    def _products_with_ledgers(self):
        return products_with_ledgers(self.domain, self._sp_ids,
                                     STOCK_SECTION_TYPE,
                                     self._program_product_ids)

    @cached_property
    def _desc_product_order(self):
        return self.request.GET.get('sSortDir_0') == 'desc'

    @property
    def total_records(self):
        return len(self._products_with_ledgers)

    @classmethod
    def display_in_dropdown(cls, domain=None, project=None, user=None):
        return True

    @property
    def headers(self):
        columns = [
            DataTablesColumn(_('Product')),
            DataTablesColumn(_('# Facilities'), sortable=False),
            DataTablesColumn(
                _('Stocked Out'),
                help_text=_("A facility is counted as stocked out when its \
                            current stock is below the emergency level."),
                sortable=False),
            DataTablesColumn(
                _('Understocked'),
                help_text=_("A facility is counted as under stocked when its \
                            current stock is above the emergency level but below the \
                            low stock level."),
                sortable=False),
            DataTablesColumn(
                _('Adequate Stock'),
                help_text=_("A facility is counted as adequately stocked when \
                            its current stock is above the low level but below the \
                            overstock level."),
                sortable=False),
            DataTablesColumn(
                _('Overstocked'),
                help_text=_("A facility is counted as overstocked when \
                            its current stock is above the overstock level."),
                sortable=False),
            DataTablesColumn(
                _('Insufficient Data'),
                help_text=_("A facility is marked as insufficient data when \
                            there is no known consumption amount or there \
                            has never been a stock report at the location. \
                            Consumption amount can be unknown if there is \
                            either no default consumption value or the reporting \
                            history does not meet the calculation settings \
                            for the project."),
                sortable=False)
        ]
        return DataTablesHeader(*columns)

    @cached_property
    def product_data(self):
        return list(self.get_prod_data())

    def filter_by_product_ids(self):
        """
        This sorts by name of products that should be shown according to filter and
        then returns the product ids to be shown according to the pagination
        """
        product_name_map = self._product_name_mapping
        # sort
        sorted_product_name_map = sorted(product_name_map.items(),
                                         key=lambda name_map: name_map[1],
                                         reverse=self._desc_product_order)
        # product to filter
        # -> that have ledgers and
        # -> fall into requested pagination
        return [
            product_id for product_id, product_name in sorted_product_name_map
            if product_id in self._products_with_ledgers
        ][self.pagination.start:][:self.pagination.count]

    def get_prod_data(self):
        ledger_values = get_wrapped_ledger_values(
            domain=self.domain,
            case_ids=self._sp_ids,
            section_id=STOCK_SECTION_TYPE,
            entry_ids=self.filter_by_product_ids(),
        )
        product_grouping = {}
        for ledger_value in ledger_values:
            consumption_helper = get_consumption_helper_from_ledger_value(
                self.domain, ledger_value)
            status = consumption_helper.get_stock_category()
            if ledger_value.entry_id in product_grouping:
                product_grouping[ledger_value.entry_id][status] += 1
                product_grouping[ledger_value.entry_id]['facility_count'] += 1

            else:
                product_grouping[ledger_value.entry_id] = {
                    'entry_id': ledger_value.entry_id,
                    'stockout': 0,
                    'understock': 0,
                    'overstock': 0,
                    'adequate': 0,
                    'nodata': 0,
                    'facility_count': 1
                }
                product_grouping[ledger_value.entry_id][status] = 1
        product_name_map = self._product_name_mapping
        rows = [[
            product_name_map.get(product['entry_id'], product['entry_id']),
            product['facility_count'],
            100.0 * product['stockout'] / product['facility_count'],
            100.0 * product['understock'] / product['facility_count'],
            100.0 * product['adequate'] / product['facility_count'],
            100.0 * product['overstock'] / product['facility_count'],
            100.0 * product['nodata'] / product['facility_count'],
        ] for product in product_grouping.values()]

        return sorted(rows,
                      key=lambda r: r[0].lower(),
                      reverse=self._desc_product_order)

    @property
    def rows(self):
        return [
            pd[0:2] + ['%.1f%%' % d for d in pd[2:]]
            for pd in self.product_data
        ]

    @property
    def get_all_rows(self):
        self.pagination.count = self.total_records
        return self.rows
示例#48
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, *args, **kwargs):
        return super(BaseMessagingSectionView, self).dispatch(*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),
        }

    @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 post(self, *args, **kwargs):
        action = self.request.POST.get('action')
        if action in [ACTION_ACTIVATE, ACTION_DEACTIVATE, ACTION_DELETE]:
            return HttpResponse(json.dumps(self.get_action_response(action)))
        return HttpResponse(status=400)
示例#49
0
class InventoryReport(GenericTabularReport, CommtrackReportMixin):
    name = ugettext_noop('Aggregate Inventory')
    slug = StockStatusDataSource.slug
    fields = [
        'corehq.apps.reports.filters.fixtures.AsyncLocationFilter',
        'corehq.apps.reports.filters.commtrack.ProgramFilter',
        'corehq.apps.reports.filters.commtrack.AdvancedColumns',
    ]
    exportable = True
    emailable = True

    @classmethod
    def display_in_dropdown(cls, domain=None, project=None, user=None):
        return True

    def showing_advanced_columns(self):
        return AdvancedColumns.get_value(self.request, self.domain)

    @property
    def headers(self):
        columns = [
            DataTablesColumn(_('Product')),
            DataTablesColumn(
                _('Stock on Hand'),
                help_text=
                _('Total stock on hand for all locations matching the filters.'
                  )),
        ]

        if self.showing_advanced_columns():
            columns += [
                DataTablesColumn(
                    _('Monthly Consumption'),
                    help_text=
                    _('Total average monthly consumption for all locations matching the filters.'
                      )),
                DataTablesColumn(
                    _('Months of Stock'),
                    help_text=
                    _('Number of months of stock remaining for all locations matching the filters. \
                                Computed by calculating stock on hand divided by monthly consumption.'
                      )),
                DataTablesColumn(
                    _('Stock Status'),
                    help_text=
                    _('Stock status prediction made using calculated consumption \
                                or project specific default values. "No Data" means that \
                                there is not enough data to compute consumption and default \
                                values have not been uploaded yet.')),
                # DataTablesColumn(_('Resupply Quantity Suggested')),
            ]

        return DataTablesHeader(*columns)

    @property
    @memoized
    def product_data(self):
        config = {
            'domain': self.domain,
            'location_id': self.request.GET.get('location_id'),
            'program_id': self.request.GET.get('program'),
            'aggregate': True,
            'advanced_columns': self.showing_advanced_columns(),
        }
        return list(StockStatusDataSource(config).get_data())

    @property
    def rows(self):
        def fmt(val, formatter=lambda k: k, default='\u2014'):
            return formatter(val) if val is not None else default

        statuses = {
            'nodata': _('no data'),
            'stockout': _('stock-out'),
            'understock': _('under-stock'),
            'adequate': _('adequate'),
            'overstock': _('over-stock'),
        }

        for row in sorted(
                self.product_data,
                key=lambda p: p[StockStatusDataSource.SLUG_PRODUCT_NAME]):
            result = [
                fmt(row[StockStatusDataSource.SLUG_PRODUCT_NAME]),
                fmt(row[StockStatusDataSource.SLUG_CURRENT_STOCK]),
            ]
            if self.showing_advanced_columns():
                result += [
                    fmt(row[StockStatusDataSource.SLUG_CONSUMPTION], int),
                    fmt(row[StockStatusDataSource.SLUG_MONTHS_REMAINING],
                        lambda k: '%.1f' % k),
                    fmt(row[StockStatusDataSource.SLUG_CATEGORY],
                        lambda k: statuses.get(k, k)),
                ]
            yield result
示例#50
0
class AddStructuredKeywordView(BaseMessagingSectionView):
    urlname = 'add_structured_keyword'
    page_title = ugettext_noop("New Structured Keyword")
    template_name = 'reminders/keyword.html'
    process_structured_message = True

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

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

    @property
    @memoized
    def keyword(self):
        return Keyword(domain=self.domain)

    @property
    def keyword_form(self):
        raise NotImplementedError("you must implement keyword_form")

    @property
    def page_context(self):
        return {
            'form': self.keyword_form,
            'form_list': get_form_list(self.domain),
        }

    @property
    @memoized
    def keyword_form(self):
        if self.request.method == 'POST':
            return KeywordForm(
                self.request.POST, domain=self.domain,
                process_structured=self.process_structured_message,
            )
        return KeywordForm(
            domain=self.domain,
            process_structured=self.process_structured_message,
        )

    def post(self, request, *args, **kwargs):
        if self.keyword_form.is_valid():
            with transaction.atomic():
                self.keyword.keyword = self.keyword_form.cleaned_data['keyword']
                self.keyword.description = self.keyword_form.cleaned_data['description']
                self.keyword.delimiter = self.keyword_form.cleaned_data['delimiter']
                self.keyword.override_open_sessions = self.keyword_form.cleaned_data['override_open_sessions']

                self.keyword.initiator_doc_type_filter = []
                if self.keyword_form.cleaned_data['allow_keyword_use_by'] == 'users':
                    self.keyword.initiator_doc_type_filter.append('CommCareUser')
                if self.keyword_form.cleaned_data['allow_keyword_use_by'] == 'cases':
                    self.keyword.initiator_doc_type_filter.append('CommCareCase')

                self.keyword.save()

                self.keyword.keywordaction_set.all().delete()
                if self.keyword_form.cleaned_data['sender_content_type'] != NO_RESPONSE:
                    self.keyword.keywordaction_set.create(
                        recipient=KeywordAction.RECIPIENT_SENDER,
                        action=self.keyword_form.cleaned_data['sender_content_type'],
                        message_content=self.keyword_form.cleaned_data['sender_message'],
                        form_unique_id=self.keyword_form.cleaned_data['sender_form_unique_id'],
                    )
                if self.process_structured_message:
                    self.keyword.keywordaction_set.create(
                        recipient=KeywordAction.RECIPIENT_SENDER,
                        action=KeywordAction.ACTION_STRUCTURED_SMS,
                        form_unique_id=self.keyword_form.cleaned_data['structured_sms_form_unique_id'],
                        use_named_args=self.keyword_form.cleaned_data['use_named_args'],
                        named_args=self.keyword_form.cleaned_data['named_args'],
                        named_args_separator=self.keyword_form.cleaned_data['named_args_separator'],
                    )
                if self.keyword_form.cleaned_data['other_recipient_content_type'] != NO_RESPONSE:
                    self.keyword.keywordaction_set.create(
                        recipient=self.keyword_form.cleaned_data['other_recipient_type'],
                        recipient_id=self.keyword_form.cleaned_data['other_recipient_id'],
                        action=self.keyword_form.cleaned_data['other_recipient_content_type'],
                        message_content=self.keyword_form.cleaned_data['other_recipient_message'],
                        form_unique_id=self.keyword_form.cleaned_data['other_recipient_form_unique_id'],
                    )

                return HttpResponseRedirect(reverse(KeywordsListView.urlname, args=[self.domain]))
        return self.get(request, *args, **kwargs)
示例#51
0
class DistrictMonthly(BaseReport):
    fields = [
        'corehq.apps.reports.filters.dates.DatespanFilter',
        'custom.reports.mc.reports.fields.DistrictField',
    ]
    slug = 'district_monthly_ucr'
    name = ugettext_noop("mc_report_dist_monthly")
    section = DISTRICT_MONTHLY_REPORT

    @property
    def columns(self):
        return [
            self.first_column,
            DatabaseColumn(_('home_visits_pregnant'),
                           CountColumn('home_visit', alias="home_visits_pregnant",
                                       filters=self.filters + [EQ('home_visit', 'one')])),
            DatabaseColumn(_('home_visits_postpartem'),
                           CountColumn('post_partem', alias="home_visits_postpartem",
                                       filters=self.filters + [EQ('post_partem', 'one')])),
            DatabaseColumn(_('home_visits_newborn'),
                           CountColumn('doc_id', alias="home_visits_newborn",
                                       filters=self.filters + [OR([EQ('newborn_reg', 'one'),
                                                                   EQ('newborn_followup', 'one')])])),
            DatabaseColumn(_('home_visits_children'),
                           CountColumn('doc_id', alias="home_visits_children",
                                       filters=self.filters + [OR([EQ('child_reg', 'one'),
                                                                   EQ('child_followup', 'one')])])),
            DatabaseColumn(_('home_visits_other'),
                           CountColumn('doc_id', alias="home_visits_other",
                                       filters=self.filters + [OR([
                                           AND([EQ('home_visit', 'zero'), EQ('post_partem', 'zero')]),
                                           EQ('sex', 'one'),
                                           EQ('adult_followup', 'one')])])),
            AggregateColumn(_("home_visits_total"), add_all, [
                AliasColumn("home_visits_pregnant"),
                AliasColumn("home_visits_postpartem"),
                AliasColumn("home_visits_newborn"),
                AliasColumn("home_visits_children"),
                AliasColumn("home_visits_other"),
            ], slug='home_visits_total'),
            DatabaseColumn(_('rdt_positive_children'),
                           CountColumn('doc_id', alias='rdt_positive_children',
                                       filters=self.filters + [EQ('rdt_children', 'one')])),
            DatabaseColumn(_('rdt_positive_adults'),
                           CountColumn('doc_id', alias='rdt_positive_adults',
                                       filters=self.filters + [EQ('rdt_adult', 'one')])),
            DatabaseColumn(_('rdt_others'),
                           CountColumn('doc_id', alias='rdt_others',
                                       filters=self.filters + [OR([EQ('rdt_adult', 'zero'),
                                                                   EQ('rdt_children', 'zero')])])),
            AggregateColumn(_('rdt_total'), add_all, [
                AliasColumn('rdt_positive_children'),
                AliasColumn('rdt_positive_adults'),
                AliasColumn('rdt_others')
            ], slug='rdt_total'),
            DatabaseColumn(_('diagnosed_malaria_child'),
                           CountColumn('malaria_child', alias='diagnosed_malaria_child',
                                       filters=self.filters + [EQ('malaria_child', 'one')])),
            DatabaseColumn(_('diagnosed_malaria_adult'),
                           CountColumn('malaria_adult', alias='diagnosed_malaria_adult',
                                       filters=self.filters + [EQ('malaria_adult', 'one')])),
            DatabaseColumn(_('diagnosed_diarrhea'),
                           CountColumn('doc_id', alias='diagnosed_diarrhea',
                                       filters=self.filters + [OR([
                                           EQ('diarrhea_child', 'one'),
                                           EQ('diarrhea_adult', 'one')
                                       ])])),
            DatabaseColumn(_('diagnosed_ari'),
                           CountColumn('doc_id', alias='diagnosed_ari',
                                       filters=self.filters + [OR([
                                           EQ('ari_child', 'one'),
                                           EQ('ari_adult', 'one')
                                       ])])),
            AggregateColumn(_('diagnosed_total'), add_all, [
                AliasColumn('diagnosed_malaria_child'),
                AliasColumn('diagnosed_malaria_adult'),
                AliasColumn('diagnosed_diarrhea'),
                AliasColumn('diagnosed_ari')
            ], slug='diagnosed_total'),
            DatabaseColumn(_('treated_malaria'),
                           CountColumn('doc_id', alias='treated_malaria', filters=self.filters + [OR([
                               AND([EQ('it_malaria_child', 'one'), EQ('malaria_child', 'one')]),
                               AND([EQ('it_malaria_adult', 'one'), EQ('malaria_adult', 'one')])
                           ])])),
            DatabaseColumn(_('treated_diarrhea'),
                           CountColumn('doc_id', alias='treated_diarrhea', filters=self.filters + [OR([
                               AND([EQ('diarrhea_child', 'one'), EQ('it_diarrhea_child', 'one')]),
                               AND([EQ('diarrhea_adult', 'one'), EQ('it_diarrhea_adult', 'one')])
                           ])])),
            DatabaseColumn(_('treated_ari'),
                           CountColumn('doc_id', alias='treated_ari', filters=self.filters + [OR([
                               AND([EQ('ari_child', 'one'), EQ('it_ari_child', 'one')]),
                               AND([EQ('ari_adult', 'one'), EQ('it_ari_adult', 'one')])
                           ])])),
            AggregateColumn(_('treated_total'), add_all, [
                AliasColumn('treated_malaria'),
                AliasColumn('treated_diarrhea'),
                AliasColumn('treated_ari')
            ], slug='treated_total'),
            DatabaseColumn(_('transfer_malnutrition'),
                           CountColumn('doc_id', alias='transfer_malnutrition', filters=self.filters + [OR([
                               EQ('malnutrition_child', 'one'),
                               EQ('malnutrition_adult', 'one')
                           ])])),
            DatabaseColumn(_('transfer_incomplete_vaccination'),
                           CountColumn('doc_id', alias='transfer_incomplete_vaccination',
                                       filters=self.filters + [OR([
                                           EQ('vaccination_child', 'one'),
                                           EQ('vaccination_adult', 'one'),
                                           EQ('vaccination_newborn', 'one')
                                       ])])),
            DatabaseColumn(_('transfer_danger_signs'),
                           CountColumn('doc_id', alias='transfer_danger_signs', filters=self.filters + [OR([
                               EQ('danger_sign_child', 'one'),
                               EQ('danger_sign_adult', 'one'),
                               EQ('danger_sign_newborn', 'one')
                           ])])),
            DatabaseColumn(_('transfer_prenatal_consult'),
                           CountColumn('doc_id', alias='transfer_prenatal_consult',
                                       filters=self.filters + [EQ('prenatal_consult', 'one')])),
            DatabaseColumn(_('transfer_missing_malaria_meds'),
                           CountColumn('doc_id', alias='transfer_missing_malaria_meds',
                                       filters=self.filters + [OR([
                                           EQ('missing_malaria_meds_child', 'one'),
                                           EQ('missing_malaria_meds_adult', 'one')
                                       ])])),
            DatabaseColumn(_('transfer_other'),
                           CountColumn('doc_id', alias='transfer_other', filters=self.filters + [OR([
                               EQ('other_child', 'one'),
                               EQ('other_adult', 'one'),
                               EQ('other_newborn', 'one')
                           ])])),
            AggregateColumn(_('transfer_total'), add_all, [
                AliasColumn('transfer_malnutrition'),
                AliasColumn('transfer_incomplete_vaccination'),
                AliasColumn('transfer_danger_signs'),
                AliasColumn('transfer_prenatal_consult'),
                AliasColumn('transfer_missing_malaria_meds'),
                AliasColumn('transfer_other'),
            ], slug='transfer_total'),
            DatabaseColumn(_('deaths_newborn'),
                           CountColumn('doc_id', alias='deaths_newborn',
                                       filters=self.filters + [EQ('deaths_newborn', 'one')])),
            DatabaseColumn(_('deaths_children'),
                           CountColumn('doc_id', alias='deaths_children',
                                       filters=self.filters + [EQ('deaths_children', 'one')])),
            DatabaseColumn(_('deaths_mothers'),
                           CountColumn('doc_id', alias='deaths_mothers',
                                       filters=self.filters + [EQ('deaths_mothers', 'one')])),
            DatabaseColumn(_('deaths_others'),
                           SumColumn('deaths_others', alias='deaths_other',
                                       filters=self.filters + [NOTEQ('deaths_others', 'zero')])),
            AggregateColumn(_('deaths_total'), add_all, [
                AliasColumn('deaths_newborn'),
                AliasColumn('deaths_children'),
                AliasColumn('deaths_mothers'),
                AliasColumn('deaths_other'),
            ], slug='deaths_total'),
            DatabaseColumn(_('heath_ed_talks'),
                           SumColumn('heath_ed_talks', alias='heath_ed_talks',
                                       filters=self.filters + [NOTEQ('heath_ed_talks', 'zero')])),
            DatabaseColumn(_('heath_ed_participants'),
                           SumColumn('heath_ed_participants', alias='heath_ed_participants',
                                     filters=self.filters + [NOTEQ('heath_ed_participants', 'zero')]))
        ]
示例#52
0
class DeIdFormExportListView(FormExportListView, DeIdFormExportListHelper):
    page_title = ugettext_noop("Export De-Identified Form Data")
    urlname = 'list_form_deid_exports'
示例#53
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
示例#54
0
class MobileWorkerListView(JSONResponseMixin, BaseUserSettingsView):
    template_name = 'users/mobile_workers.html'
    urlname = 'mobile_workers'
    page_title = ugettext_noop("Mobile Workers")

    @method_decorator(require_can_edit_or_view_commcare_users)
    def dispatch(self, *args, **kwargs):
        return super(MobileWorkerListView, self).dispatch(*args, **kwargs)

    @property
    @memoized
    def can_access_all_locations(self):
        return self.couch_user.has_permission(self.domain,
                                              'access_all_locations')

    @property
    def can_bulk_edit_users(self):
        return has_privilege(
            self.request,
            privileges.BULK_USER_MANAGEMENT) and not self.request.is_view_only

    @property
    def can_add_extra_users(self):
        return can_add_extra_mobile_workers(self.request)

    @property
    @memoized
    def new_mobile_worker_form(self):
        if self.request.method == "POST":
            return NewMobileWorkerForm(self.request.project, self.couch_user,
                                       self.request.POST)
        return NewMobileWorkerForm(self.request.project, self.couch_user)

    @property
    def _mobile_worker_form(self):
        return self.new_mobile_worker_form

    @property
    @memoized
    def custom_data(self):
        return CustomDataEditor(
            field_view=UserFieldsView,
            domain=self.domain,
            post_dict=self.request.POST
            if self.request.method == "POST" else None,
            required_only=True,
            ko_model="custom_fields",
        )

    @property
    def page_context(self):
        if FILTERED_BULK_USER_DOWNLOAD.enabled(self.domain):
            bulk_download_url = reverse(FilteredUserDownload.urlname,
                                        args=[self.domain])
        else:
            bulk_download_url = reverse("download_commcare_users",
                                        args=[self.domain])
        return {
            'new_mobile_worker_form':
            self.new_mobile_worker_form,
            'custom_fields_form':
            self.custom_data.form,
            'custom_field_slugs': [f.slug for f in self.custom_data.fields],
            'can_bulk_edit_users':
            self.can_bulk_edit_users,
            'can_add_extra_users':
            self.can_add_extra_users,
            'can_access_all_locations':
            self.can_access_all_locations,
            'draconian_security':
            settings.ENABLE_DRACONIAN_SECURITY_FEATURES,
            'pagination_limit_cookie_name':
            ('hq.pagination.limit.mobile_workers_list.%s' % self.domain),
            'can_edit_billing_info':
            self.request.couch_user.is_domain_admin(self.domain),
            'strong_mobile_passwords':
            self.request.project.strong_mobile_passwords,
            'implement_password_obfuscation':
            settings.OBFUSCATE_PASSWORD_FOR_NIC_COMPLIANCE,
            'bulk_download_url':
            bulk_download_url
        }

    @property
    @memoized
    def query(self):
        return self.request.GET.get('query')

    @allow_remote_invocation
    def check_username(self, in_data):
        try:
            username = in_data['username'].strip()
        except KeyError:
            return HttpResponseBadRequest('You must specify a username')
        if username == 'admin' or username == 'demo_user':
            return {'error': _('Username {} is reserved.').format(username)}
        try:
            validate_email("{}@example.com".format(username))
            if BAD_MOBILE_USERNAME_REGEX.search(username) is not None:
                raise ValidationError(
                    "Username contained an invalid character")
        except ValidationError:
            if '..' in username:
                return {
                    'error':
                    _("Username may not contain consecutive . (period).")
                }
            if username.endswith('.'):
                return {'error': _("Username may not end with a . (period).")}
            return {'error': _("Username may not contain special characters.")}

        full_username = format_username(username, self.domain)
        exists = user_exists(full_username)
        if exists.exists:
            if exists.is_deleted:
                result = {
                    'warning':
                    _('Username {} belonged to a user that was deleted.'
                      ' Reusing it may have unexpected consequences.').format(
                          username)
                }
            else:
                result = {
                    'error': _('Username {} is already taken').format(username)
                }
        else:
            result = {
                'success': _('Username {} is available').format(username)
            }
        return result

    @allow_remote_invocation
    def create_mobile_worker(self, in_data):
        if self.request.is_view_only:
            return {
                'error':
                _("You do not have permission to create mobile workers.")
            }

        try:
            self._ensure_proper_request(in_data)
            form_data = self._construct_form_data(in_data)
        except InvalidMobileWorkerRequest as e:
            return {'error': str(e)}

        self.request.POST = form_data

        is_valid = lambda: self._mobile_worker_form.is_valid(
        ) and self.custom_data.is_valid()
        if not is_valid():
            return {'error': _("Forms did not validate")}

        couch_user = self._build_commcare_user()

        return {
            'success': True,
            'user_id': couch_user.userID,
        }

    def _build_commcare_user(self):
        username = self.new_mobile_worker_form.cleaned_data['username']
        password = self.new_mobile_worker_form.cleaned_data['new_password']
        first_name = self.new_mobile_worker_form.cleaned_data['first_name']
        last_name = self.new_mobile_worker_form.cleaned_data['last_name']
        location_id = self.new_mobile_worker_form.cleaned_data['location_id']

        return CommCareUser.create(
            self.domain,
            username,
            password,
            device_id="Generated from HQ",
            first_name=first_name,
            last_name=last_name,
            user_data=self.custom_data.get_data_to_save(),
            location=SQLLocation.objects.get(
                location_id=location_id) if location_id else None,
        )

    def _ensure_proper_request(self, in_data):
        if not self.can_add_extra_users:
            raise InvalidMobileWorkerRequest(_("No Permission."))

        if 'user' not in in_data:
            raise InvalidMobileWorkerRequest(
                _("Please provide mobile worker data."))

        return None

    def _construct_form_data(self, in_data):
        try:
            user_data = in_data['user']
            form_data = {
                'username': user_data.get('username'),
                'new_password': user_data.get('password'),
                'first_name': user_data.get('first_name'),
                'last_name': user_data.get('last_name'),
                'location_id': user_data.get('location_id'),
                'domain': self.domain,
            }
            for k, v in user_data.get('custom_fields', {}).items():
                form_data["{}-{}".format(CUSTOM_DATA_FIELD_PREFIX, k)] = v
            return form_data
        except Exception as e:
            raise InvalidMobileWorkerRequest(
                _("Check your request: {}".format(e)))
示例#55
0
class EditStructuredKeywordView(AddStructuredKeywordView):
    urlname = 'edit_structured_keyword'
    page_title = ugettext_noop("Edit Structured Keyword")

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

    @property
    def keyword_id(self):
        return self.kwargs.get('keyword_id')

    @property
    @memoized
    def keyword(self):
        if not self.keyword_id:
            raise Http404()

        try:
            k = Keyword.objects.get(couch_id=self.keyword_id)
        except Keyword.DoesNotExist:
            raise Http404()

        if k.domain != self.domain:
            raise Http404()

        return k

    @property
    @memoized
    def keyword_form(self):
        initial = self.get_initial_values()
        if self.request.method == 'POST':
            form = KeywordForm(
                self.request.POST, domain=self.domain, initial=initial,
                process_structured=self.process_structured_message,
            )
            form._sk_id = self.keyword_id
            return form
        return KeywordForm(
            domain=self.domain, initial=initial,
            process_structured=self.process_structured_message,
        )

    def get_initial_values(self):
        initial = {
            'keyword': self.keyword.keyword,
            'description': self.keyword.description,
            'delimiter': self.keyword.delimiter,
            'override_open_sessions': self.keyword.override_open_sessions,
            'sender_content_type': NO_RESPONSE,
        }
        is_case_filter = "CommCareCase" in self.keyword.initiator_doc_type_filter
        is_user_filter = "CommCareUser" in self.keyword.initiator_doc_type_filter
        if is_case_filter and not is_user_filter:
            initial.update({
                'allow_keyword_use_by': 'cases',
            })
        elif is_user_filter and not is_case_filter:
            initial.update({
                'allow_keyword_use_by': 'users',
            })
        for action in self.keyword.keywordaction_set.all():
            if action.action == KeywordAction.ACTION_STRUCTURED_SMS:
                if self.process_structured_message:
                    initial.update({
                        'structured_sms_form_unique_id': action.form_unique_id,
                        'use_custom_delimiter': self.keyword.delimiter is not None,
                        'use_named_args_separator': action.named_args_separator is not None,
                        'use_named_args': action.use_named_args,
                        'named_args_separator': action.named_args_separator,
                        'named_args': [{"name" : k, "xpath" : v} for k, v in action.named_args.items()],
                    })
            elif action.recipient == KeywordAction.RECIPIENT_SENDER:
                initial.update({
                    'sender_content_type': action.action,
                    'sender_message': action.message_content,
                    'sender_form_unique_id': action.form_unique_id,
                })
            else:
                initial.update({
                    'other_recipient_type': action.recipient,
                    'other_recipient_id': action.recipient_id,
                    'other_recipient_content_type': action.action,
                    'other_recipient_message': action.message_content,
                    'other_recipient_form_unique_id': action.form_unique_id,
                })
        return initial
示例#56
0
class ConfirmBillingAccountForExtraUsersView(BaseUserSettingsView,
                                             AsyncHandlerMixin):
    urlname = 'extra_users_confirm_billing'
    template_name = 'users/extra_users_confirm_billing.html'
    page_title = ugettext_noop("Confirm Billing Information")
    async_handlers = [
        Select2BillingInfoHandler,
    ]

    @property
    @memoized
    def account(self):
        account = BillingAccount.get_or_create_account_by_domain(
            self.domain,
            created_by=self.couch_user.username,
            account_type=BillingAccountType.USER_CREATED,
            entry_point=EntryPoint.SELF_STARTED,
        )[0]
        return account

    @property
    @memoized
    def billing_info_form(self):
        if self.request.method == 'POST':
            return ConfirmExtraUserChargesForm(
                self.account,
                self.domain,
                self.request.couch_user.username,
                data=self.request.POST)
        return ConfirmExtraUserChargesForm(self.account, self.domain,
                                           self.request.couch_user.username)

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

    @method_decorator(domain_admin_required)
    def dispatch(self, request, *args, **kwargs):
        if self.account.date_confirmed_extra_charges is not None:
            return HttpResponseRedirect(
                reverse(MobileWorkerListView.urlname, args=[self.domain]))
        return super(ConfirmBillingAccountForExtraUsersView,
                     self).dispatch(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        if self.async_response is not None:
            return self.async_response
        if self.billing_info_form.is_valid():
            is_saved = self.billing_info_form.save()
            if not is_saved:
                messages.error(
                    request,
                    _("It appears that there was an issue updating your contact information. "
                      "We've been notified of the issue. Please try submitting again, and if the problem "
                      "persists, please try in a few hours."))
            else:
                messages.success(
                    request,
                    _("Billing contact information was successfully confirmed. "
                      "You may now add additional Mobile Workers."))
                return HttpResponseRedirect(
                    reverse(MobileWorkerListView.urlname, args=[self.domain]))
        return self.get(request, *args, **kwargs)
示例#57
0
def setup_motion_config(sender, **kwargs):
    """
    Motion config variables.
    """
    # General
    motion_workflow = ConfigVariable(
        name='motion_workflow',
        default_value='1',
        form_field=forms.ChoiceField(
            widget=forms.Select(),
            label=ugettext_lazy('Workflow of new motions'),
            required=True,
            choices=[(str(workflow.pk), ugettext_lazy(workflow.name))
                     for workflow in Workflow.objects.all()]))
    motion_identifier = ConfigVariable(
        name='motion_identifier',
        default_value='per_category',
        form_field=forms.ChoiceField(
            widget=forms.Select(),
            required=True,
            label=ugettext_lazy('Identifier'),
            choices=[('per_category', ugettext_lazy('Numbered per category')),
                     ('serially_numbered', ugettext_lazy('Serially numbered')),
                     ('manually', ugettext_lazy('Set it manually'))]))
    motion_preamble = ConfigVariable(
        name='motion_preamble',
        default_value=_('The assembly may decide,'),
        translatable=True,
        form_field=forms.CharField(widget=forms.TextInput(),
                                   required=False,
                                   label=ugettext_lazy('Motion preamble')))
    motion_stop_submitting = ConfigVariable(
        name='motion_stop_submitting',
        default_value=False,
        form_field=forms.BooleanField(label=ugettext_lazy(
            'Stop submitting new motions by non-staff users'),
                                      required=False))
    motion_allow_disable_versioning = ConfigVariable(
        name='motion_allow_disable_versioning',
        default_value=False,
        form_field=forms.BooleanField(
            label=ugettext_lazy('Allow to disable versioning'),
            required=False))
    group_general = ConfigGroup(
        title=ugettext_lazy('General'),
        variables=(motion_workflow, motion_identifier, motion_preamble,
                   motion_stop_submitting, motion_allow_disable_versioning))

    # Supporters
    motion_min_supporters = ConfigVariable(
        name='motion_min_supporters',
        default_value=0,
        form_field=forms.IntegerField(
            widget=forms.TextInput(attrs={'class': 'small-input'}),
            label=ugettext_lazy(
                'Number of (minimum) required supporters for a motion'),
            min_value=0,
            help_text=ugettext_lazy(
                'Choose 0 to disable the supporting system.')))
    motion_remove_supporters = ConfigVariable(
        name='motion_remove_supporters',
        default_value=False,
        form_field=forms.BooleanField(label=ugettext_lazy(
            'Remove all supporters of a motion if a submitter edits his motion in early state'
        ),
                                      required=False))
    group_supporters = ConfigGroup(title=ugettext_lazy('Supporters'),
                                   variables=(motion_min_supporters,
                                              motion_remove_supporters))

    # Voting and ballot papers
    motion_poll_100_percent_base = ConfigVariable(
        name='motion_poll_100_percent_base',
        default_value='WITHOUT_INVALID',
        form_field=forms.ChoiceField(
            widget=forms.Select(),
            required=False,
            label=ugettext_lazy(
                'The 100 % base of a voting result consists of'),
            choices=PERCENT_BASE_CHOICES))
    motion_pdf_ballot_papers_selection = ConfigVariable(
        name='motion_pdf_ballot_papers_selection',
        default_value='CUSTOM_NUMBER',
        form_field=forms.ChoiceField(
            widget=forms.Select(),
            required=False,
            label=ugettext_lazy('Number of ballot papers (selection)'),
            choices=[('NUMBER_OF_DELEGATES',
                      ugettext_lazy('Number of all delegates')),
                     ('NUMBER_OF_ALL_PARTICIPANTS',
                      ugettext_lazy('Number of all participants')),
                     ('CUSTOM_NUMBER',
                      ugettext_lazy("Use the following custom number"))]))
    motion_pdf_ballot_papers_number = ConfigVariable(
        name='motion_pdf_ballot_papers_number',
        default_value=8,
        form_field=forms.IntegerField(
            widget=forms.TextInput(attrs={'class': 'small-input'}),
            required=False,
            min_value=1,
            label=ugettext_lazy('Custom number of ballot papers')))
    group_ballot_papers = ConfigGroup(
        title=ugettext_lazy('Voting and ballot papers'),
        variables=(motion_poll_100_percent_base,
                   motion_pdf_ballot_papers_selection,
                   motion_pdf_ballot_papers_number))

    # PDF
    motion_pdf_title = ConfigVariable(
        name='motion_pdf_title',
        default_value=_('Motions'),
        translatable=True,
        form_field=forms.CharField(
            widget=forms.TextInput(),
            required=False,
            label=ugettext_lazy('Title for PDF document (all motions)')))
    motion_pdf_preamble = ConfigVariable(
        name='motion_pdf_preamble',
        default_value='',
        form_field=forms.CharField(
            widget=forms.Textarea(),
            required=False,
            label=ugettext_lazy(
                'Preamble text for PDF document (all motions)')))
    motion_pdf_paragraph_numbering = ConfigVariable(
        name='motion_pdf_paragraph_numbering',
        default_value=False,
        form_field=forms.BooleanField(
            label=ugettext_lazy('Show paragraph numbering (only in PDF)'),
            required=False))
    group_pdf = ConfigGroup(title=ugettext_lazy('PDF'),
                            variables=(motion_pdf_title, motion_pdf_preamble,
                                       motion_pdf_paragraph_numbering))

    return ConfigGroupedCollection(title=ugettext_noop('Motion'),
                                   url='motion',
                                   weight=30,
                                   groups=(group_general, group_supporters,
                                           group_ballot_papers, group_pdf))
示例#58
0
class FormExportListView(BaseExportListView, FormExportListHelper):
    urlname = 'list_form_exports'
    page_title = ugettext_noop("Export Form Data")
示例#59
0
import dateutil
from corehq.apps.app_manager.models import ApplicationBase
from corehq.apps.domain.models import Domain
from casexml.apps.case.models import CommCareCase
from datetime import datetime, timedelta
from pytz import timezone

EMPTY_FIELD = "---"
SUCCEED_DOMAIN = 'succeed'
SUCCEED_CM_APPNAME = 'SUCCEED CM app'
SUCCEED_PM_APPNAME = 'SUCCEED PM app'
SUCCEED_CHW_APPNAME = 'SUCCEED CHW app'

CONFIG = {
    'groups': [
        dict(val="harbor", text=ugettext_noop("Harbor UCLA")),
        dict(val="lac-usc", text=ugettext_noop("LAC-USC")),
        dict(val="oliveview", text=ugettext_noop("Olive View Medical Center")),
        dict(val="rancho", text=ugettext_noop("Rancho Los Amigos")),
    ],
    'succeed_admin':
    'SUCCEED Admin',
    'pm_role':
    'Project Manager',
    'pi_role':
    'Principal Investigator',
    'cm_role':
    'Care Manager',
    'chw_role':
    'Community Health Worker'
}
示例#60
0
class EditCommCareUserView(BaseEditUserView):
    urlname = "edit_commcare_user"
    page_title = ugettext_noop("Edit Mobile Worker")

    @property
    def page_name(self):
        if self.request.is_view_only:
            return _("Edit Mobile Worker (View Only)")
        return self.page_title

    @property
    def template_name(self):
        if self.editable_user.is_deleted():
            return "users/deleted_account.html"
        else:
            return "users/edit_commcare_user.html"

    @use_multiselect
    @method_decorator(require_can_edit_or_view_commcare_users)
    def dispatch(self, request, *args, **kwargs):
        return super(EditCommCareUserView,
                     self).dispatch(request, *args, **kwargs)

    @property
    def main_context(self):
        context = super(EditCommCareUserView, self).main_context
        context.update({
            'edit_user_form_title': self.edit_user_form_title,
            'strong_mobile_passwords':
            self.request.project.strong_mobile_passwords,
            'implement_password_obfuscation':
            settings.OBFUSCATE_PASSWORD_FOR_NIC_COMPLIANCE,
            'has_any_sync_logs': self.has_any_sync_logs,
        })
        return context

    @property
    def has_any_sync_logs(self):
        return SyncLogSQL.objects.filter(
            user_id=self.editable_user_id).exists()

    @property
    @memoized
    def editable_user(self):
        try:
            user = CouchUser.get_by_user_id(self.editable_user_id, self.domain)
        except (ResourceNotFound, CouchUser.AccountTypeError, KeyError):
            raise Http404()
        if not user or not _can_edit_workers_location(self.couch_user, user):
            raise Http404()
        return user

    @property
    def edit_user_form_title(self):
        return _("Information for %s") % self.editable_user.human_friendly_name

    @property
    def is_currently_logged_in_user(self):
        return self.editable_user_id == self.couch_user._id

    @property
    def is_delete_allowed(self):
        from corehq.apps.couch_sql_migration.progress import couch_sql_migration_in_progress
        return not couch_sql_migration_in_progress(self.domain)

    @property
    @memoized
    def reset_password_form(self):
        return SetUserPasswordForm(self.request.project,
                                   self.editable_user_id,
                                   user="")

    @property
    @memoized
    def groups(self):
        if not self.editable_user:
            return []
        return Group.by_user_id(self.editable_user_id)

    @property
    @memoized
    def all_groups(self):
        # note: will slow things down if there are loads of groups. worth it?
        # justification: ~every report already does this.
        return Group.by_domain(self.domain)

    @property
    @memoized
    def group_form(self):
        form = MultipleSelectionForm(initial={
            'selected_ids': [g._id for g in self.groups],
        })
        form.fields['selected_ids'].choices = [(g._id, g.name)
                                               for g in self.all_groups]
        return form

    @property
    @memoized
    def commtrack_form(self):
        if self.request.method == "POST" and self.request.POST[
                'form_type'] == "commtrack":
            return CommtrackUserForm(self.request.POST, domain=self.domain)

        # currently only support one location on the UI
        linked_loc = self.editable_user.location
        initial_id = linked_loc._id if linked_loc else None
        program_id = self.editable_user.get_domain_membership(
            self.domain).program_id
        assigned_locations = self.editable_user.assigned_location_ids
        return CommtrackUserForm(domain=self.domain,
                                 initial={
                                     'primary_location': initial_id,
                                     'program_id': program_id,
                                     'assigned_locations': assigned_locations
                                 })

    @property
    def page_context(self):

        if self.request.is_view_only:
            make_form_readonly(self.commtrack_form)
            make_form_readonly(self.form_user_update.user_form)
            make_form_readonly(self.form_user_update.custom_data.form)

        context = {
            'are_groups':
            bool(len(self.all_groups)),
            'groups_url':
            reverse('all_groups', args=[self.domain]),
            'group_form':
            self.group_form,
            'reset_password_form':
            self.reset_password_form,
            'is_currently_logged_in_user':
            self.is_currently_logged_in_user,
            'is_delete_allowed':
            self.is_delete_allowed,
            'data_fields_form':
            self.form_user_update.custom_data.form,
            'can_use_inbound_sms':
            domain_has_privilege(self.domain, privileges.INBOUND_SMS),
            'can_create_groups':
            (self.request.couch_user.has_permission(self.domain, 'edit_groups')
             and self.request.couch_user.has_permission(
                 self.domain, 'access_all_locations')),
            'needs_to_downgrade_locations':
            (users_have_locations(self.domain)
             and not has_privilege(self.request, privileges.LOCATIONS)),
            'demo_restore_date':
            naturaltime(demo_restore_date_created(self.editable_user)),
            'hide_password_feedback':
            settings.ENABLE_DRACONIAN_SECURITY_FEATURES,
            'group_names': [g.name for g in self.groups],
        }
        if self.commtrack_form.errors:
            messages.error(
                self.request,
                _("There were some errors while saving user's locations. Please check the 'Locations' tab"
                  ))
        if self.domain_object.commtrack_enabled or self.domain_object.uses_locations:
            context.update({
                'commtrack_enabled': self.domain_object.commtrack_enabled,
                'uses_locations': self.domain_object.uses_locations,
                'commtrack': {
                    'update_form': self.commtrack_form,
                },
            })
        return context

    @property
    def user_role_choices(self):
        return [('none', _('(none)'))] + self.editable_role_choices

    @property
    @memoized
    def form_user_update(self):
        if (self.request.method == "POST"
                and self.request.POST['form_type'] == "update-user"
                and not self.request.is_view_only):
            data = self.request.POST
        else:
            data = None
        form = CommCareUserFormSet(data=data,
                                   domain=self.domain,
                                   editable_user=self.editable_user,
                                   request_user=self.request.couch_user)

        form.user_form.load_language(
            language_choices=get_domain_languages(self.domain))

        if self.can_change_user_roles or self.couch_user.can_view_roles():
            form.user_form.load_roles(current_role=self.existing_role,
                                      role_choices=self.user_role_choices)
        else:
            del form.user_form.fields['role']

        return form

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

    def post(self, request, *args, **kwargs):
        if self.request.is_view_only:
            messages.error(
                request,
                _("You do not have permission to update Mobile Workers."))
            return super(EditCommCareUserView,
                         self).get(request, *args, **kwargs)
        if self.request.POST['form_type'] == "add-phonenumber":
            phone_number = self.request.POST['phone_number']
            phone_number = re.sub(r'\s', '', phone_number)
            if re.match(r'\d+$', phone_number):
                self.editable_user.add_phone_number(phone_number)
                self.editable_user.save(spawn_task=True)
                messages.success(request, _("Phone number added."))
            else:
                messages.error(request, _("Please enter digits only."))
        return super(EditCommCareUserView, self).post(request, *args, **kwargs)