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)))
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(), )
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, )
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()
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)
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})
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)
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})
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)
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
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})
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)
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)
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.")
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)
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()
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()
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()
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)
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"))
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)
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)
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
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()
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")]
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)
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)
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', ), ), )
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")]
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')
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)
class DeIdDailySavedExportListView(DailySavedExportListView, DeIdDailySavedExportListHelper): urlname = 'list_deid_daily_saved_exports' page_title = ugettext_noop("Export De-Identified Daily Saved Exports")
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
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') ])])) ]
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
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]
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')])), ]
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)
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()
class AddNormalKeywordView(AddStructuredKeywordView): urlname = 'add_normal_keyword' page_title = ugettext_noop("New Keyword") process_structured_message = False
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]))
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]))
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()
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)
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('.')
class DeIdDashboardFeedListView(DashboardFeedListView, DeIdDashboardFeedListHelper): urlname = 'list_deid_dashboard_feeds' page_title = ugettext_noop("Export De-Identified Dashboard Feeds")
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
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)
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
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)
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')])) ]
class DeIdFormExportListView(FormExportListView, DeIdFormExportListHelper): page_title = ugettext_noop("Export De-Identified Form Data") urlname = 'list_form_deid_exports'
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
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)))
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
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)
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))
class FormExportListView(BaseExportListView, FormExportListHelper): urlname = 'list_form_exports' page_title = ugettext_noop("Export Form Data")
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' }
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)