def context(self): return dict( value=format_html( u"{} <span class='timeline-arrow'></span> {}", STATES_MAP[int(to_python(self.submission.old_value))], STATES_MAP[int(to_python(self.submission.new_value))]), state=True)
def state_change_entry(self): entry = self.entry_dict entry['old_value'] = STATES_MAP[int( to_python(self.submission.old_value))] entry['new_value'] = STATES_MAP[int( to_python(self.submission.new_value))] return entry
def _get_state_changed_value(submission): params = { 'old_value': STATES_MAP[int(to_python(submission.old_value))], 'new_value': STATES_MAP[int(to_python(submission.new_value))] } return (u"%(old_value)s " u"<span class='timeline-arrow'></span> " u"%(new_value)s" % params)
def _get_state_changed_value(submission): params = { 'old_value': STATES_MAP[int(to_python(submission.old_value))], 'new_value': STATES_MAP[int(to_python(submission.new_value))]} return ( u"%(old_value)s " u"<span class='timeline-arrow'></span> " u"%(new_value)s" % params)
def get_history(request, unit): """ @return: JSON with changes to the unit rendered in HTML. """ entries = Submission.objects.filter(unit=unit, field="pootle_store.Unit.target") entries = entries.select_related("submitter__user", "translation_project__language") #: list of tuples (datetime, submitter, value) values = [] import locale from pootle_store.fields import to_python old_value = u"" language = None for entry in entries: language = entry.translation_project.language # If the old_value doesn't correspond to the previous new_value, let's # add it anyway, even if we don't have more information about it. It # might be because of an upload, VCS action, etc. that wasn't recorded. if old_value != entry.old_value: # Translators: this refers to an unknown date values.append((_("(unknown)"), u"", to_python(entry.old_value))) old_value = entry.new_value values.append(( entry.creation_time.strftime(locale.nl_langinfo(locale.D_T_FMT)), entry.submitter, to_python(old_value), )) if old_value and old_value != unit.target: values.append((_("Now"), u"", to_python(old_value))) # let's reverse the chronological order values.reverse() ec = { 'values': values, 'language': language, } if request.is_ajax(): t = loader.get_template('unit/history-xhr.html') c = RequestContext(request, ec) json = { # The client will want to confirm that the response is # relevant for the unit on screen at the time of receiving # this, so we add the uid. 'uid': unit.id, 'entries': t.render(c), } response = simplejson.dumps(json) return HttpResponse(response, mimetype="application/json") else: return render_to_response( 'unit/history.html', ec, context_instance=RequestContext(request), )
def translation_action_type(self): if not self.unit: return if self.type not in SubmissionTypes.EDIT_TYPES: return if self.field == SubmissionFields.STATE: # Note that a submission where field is STATE # should be created before a submission where # field is TARGET state = int(to_python(self.new_value)) if state == TRANSLATED: return TranslationActionTypes.REVIEWED elif state == FUZZY: return TranslationActionTypes.NEEDS_WORK if self.field != SubmissionFields.TARGET: return if self.new_value == '': return TranslationActionTypes.REMOVED # Note that we analyze current unit state: # if this submission is not last unit state # can be changed if self.unit_state not in [TRANSLATED, FUZZY]: return if self.old_value != '': return TranslationActionTypes.EDITED return (TranslationActionTypes.PRE_TRANSLATED if self.unit_state == FUZZY else TranslationActionTypes.TRANSLATED)
def unit_source_update(counter, unit_source): unit_source.source_hash = md5(force_bytes( unit_source.unit.source_f)).hexdigest() unit_source.source_length = len(unit_source.unit.source_f) unit_source.source_wordcount = max( 1, (counter.count_words(to_python(unit_source.unit.source_f)) or 0)) return unit_source
def translation_action_type(self): if not self.unit: return if self.type not in SubmissionTypes.EDIT_TYPES: return if self.field == SubmissionFields.STATE: # Note that a submission where field is STATE # should be created before a submission where # field is TARGET state = int(to_python(self.new_value)) if state == TRANSLATED: return TranslationActionTypes.REVIEWED elif state == FUZZY: return TranslationActionTypes.NEEDS_WORK if self.field != SubmissionFields.TARGET: return if self.new_value == '': return TranslationActionTypes.REMOVED # Note that we analyze current unit state: # if this submission is not last unit state # can be changed if self.unit_state not in [TRANSLATED, FUZZY]: return if self.old_value != '': return TranslationActionTypes.EDITED return ( TranslationActionTypes.PRE_TRANSLATED if self.unit_state == FUZZY else TranslationActionTypes.TRANSLATED)
def unit_source_update(counter, unit_source): unit_source.source_hash = md5( force_bytes(unit_source.unit.source_f)).hexdigest() unit_source.source_length = len(unit_source.unit.source_f) unit_source.source_wordcount = max( 1, (counter.count_words(to_python(unit_source.unit.source_f)) or 0)) return unit_source
def get_submission_message(self): """Returns a message describing the submission. The message includes the user (with link to profile and gravatar), a message describing the action performed, and when it was performed. """ unit = {} source = {} if self.unit is not None: unit = { 'source': escape(truncatechars(self.unit, 50)), 'url': self.unit.get_translate_url(), } source = { 'source_string': '<i><a href="%(url)s">%(source)s</a></i>' % unit, } if self.quality_check is not None: check_name = self.quality_check.name unit.update({ 'check_name': check_name, 'check_display_name': check_names.get(check_name, check_name), 'checks_url': reverse('pootle-checks-descriptions'), }) source.update({ 'check_name': '<a href="%(checks_url)s#%(check_name)s">' '%(check_display_name)s</a>' % unit, }) if (self.suggestion and self.type in (SubmissionTypes.SUGG_ACCEPT, SubmissionTypes.SUGG_REJECT)): displayuser = self.suggestion.reviewer else: # Sadly we may not have submitter information in all the # situations yet # TODO check if it is true if self.submitter: displayuser = self.submitter else: User = get_user_model() displayuser = User.objects.get_nobody_user() action_bundle = { "profile_url": displayuser.get_absolute_url(), "gravatar_url": displayuser.gravatar_url(20), "displayname": escape(displayuser.display_name), "username": displayuser.username, "display_datetime": dateformat.format(self.creation_time), "iso_datetime": self.creation_time.isoformat(), "action": "", } msg = { SubmissionTypes.REVERT: _( 'reverted translation for %(source_string)s', source ), SubmissionTypes.SUGG_ACCEPT: _( 'accepted suggestion for %(source_string)s', source ), SubmissionTypes.SUGG_ADD: _( 'added suggestion for %(source_string)s', source ), SubmissionTypes.SUGG_REJECT: _( 'rejected suggestion for %(source_string)s', source ), SubmissionTypes.UPLOAD: _( 'uploaded a file' ), SubmissionTypes.MUTE_CHECK: _( 'muted %(check_name)s for %(source_string)s', source ), SubmissionTypes.UNMUTE_CHECK: _( 'unmuted %(check_name)s for %(source_string)s', source ), }.get(self.type, None) #TODO Look how to detect submissions for "sent suggestion", "rejected # suggestion"... #TODO Fix bug 3011 and replace the following code with the appropiate # one in the dictionary above. if msg is None: try: if self.field == SubmissionFields.TARGET: if self.new_value != '': # Note that we analyze current unit state: # if this submission is not last unit state # can be changed if self.unit.state == TRANSLATED: if self.old_value == '': msg = _('translated %(source_string)s', source) else: msg = _('edited %(source_string)s', source) elif self.unit.state == FUZZY: if self.old_value == '': msg = _('pre-translated %(source_string)s', source) else: msg = _('edited %(source_string)s', source) else: msg = _('removed translation for %(source_string)s', source) elif self.field == SubmissionFields.STATE: # Note that a submission where field is STATE # should be created before a submission where # field is TARGET msg = { TRANSLATED: _('reviewed %(source_string)s', source), FUZZY: _('marked as needs work %(source_string)s', source) }.get(int(to_python(self.new_value)), '') else: msg = _('unknown action %(source_string)s', source) except AttributeError: return '' action_bundle['action'] = msg return mark_safe( u'<div class="last-action">' ' <a href="%(profile_url)s">' ' <img src="%(gravatar_url)s" />' ' <span title="%(username)s">%(displayname)s</span>' ' </a>' ' <span class="action-text">%(action)s</span>' ' <time class="extra-item-meta js-relative-date"' ' title="%(display_datetime)s" datetime="%(iso_datetime)s"> ' ' </time>' '</div>' % action_bundle)
def _calculate_timeline(request, unit): submission_filter = (Q(field__in=[ SubmissionFields.TARGET, SubmissionFields.STATE, SubmissionFields.COMMENT, SubmissionFields.NONE ]) | Q(type__in=SubmissionTypes.SUGGESTION_TYPES)) timeline = (Submission.objects.filter( unit=unit).filter(submission_filter).exclude( field=SubmissionFields.COMMENT, creation_time=unit.commented_on).order_by("id")) User = get_user_model() entries_group = [] context = {} timeline_fields = [ "type", "old_value", "new_value", "submitter_id", "creation_time", "translation_project__language__code", "field", "suggestion_id", "suggestion__target_f", "quality_check__name", "submitter__username", "submitter__full_name", "suggestion__user__full_name", "submitter__email", "suggestion__user__username" ] grouped_timeline = groupby(timeline.values(*timeline_fields), key=lambda item: "\001".join([ str(x) for x in [ item['submitter_id'], item['creation_time'], item['suggestion_id'], ] ])) # Group by submitter id and creation_time because # different submissions can have same creation time for key_, values in grouped_timeline: entry_group = { 'entries': [], } for item in values: # Only add creation_time information for the whole entry group once entry_group['datetime'] = item['creation_time'] # Only add submitter information for the whole entry group once entry_group.setdefault('submitter', ProxyTimelineUser(item)) context.setdefault( 'language', ProxyTimelineLanguage( item['translation_project__language__code'])) entry = { 'field': item['field'], 'field_name': SubmissionFields.NAMES_MAP.get(item['field'], None), 'type': item['type'] } if item['field'] == SubmissionFields.STATE: entry['old_value'] = STATES_MAP[int( to_python(item['old_value']))] entry['new_value'] = STATES_MAP[int( to_python(item['new_value']))] elif item['suggestion_id']: entry.update({ 'suggestion_text': item['suggestion__target_f'], 'suggestion_description': mark_safe(_get_suggestion_description(item)) }) elif item['quality_check__name']: check_name = item['quality_check__name'] check_url = (u''.join( [reverse('pootle-checks-descriptions'), '#', check_name])) entry.update({ 'check_name': check_name, 'check_display_name': check_names[check_name], 'checks_url': check_url }) else: entry['new_value'] = to_python(item['new_value']) entry_group['entries'].append(entry) entries_group.append(entry_group) has_creation_entry = (len(entries_group) > 0 and entries_group[0]['datetime'] == unit.creation_time) if (has_creation_entry): entries_group[0]['created'] = True else: created = { 'created': True, 'submitter': User.objects.get_system_user() } if unit.creation_time: created['datetime'] = unit.creation_time entries_group[:0] = [created] # Let's reverse the chronological order entries_group.reverse() context['entries_group'] = entries_group t = loader.get_template('editor/units/xhr_timeline.html') return t.render(context, request)
def _calculate_timeline(request, unit): submission_filter = ( Q(field__in=[SubmissionFields.TARGET, SubmissionFields.STATE, SubmissionFields.COMMENT, SubmissionFields.NONE]) | Q(type__in=SubmissionTypes.SUGGESTION_TYPES)) timeline = ( Submission.objects.filter(unit=unit) .filter(submission_filter) .exclude(field=SubmissionFields.COMMENT, creation_time=unit.commented_on) .order_by("id")) User = get_user_model() entries_group = [] context = {} timeline_fields = [ "type", "old_value", "new_value", "submitter_id", "creation_time", "translation_project__language__code", "field", "suggestion_id", "suggestion__target_f", "quality_check__name", "submitter__username", "submitter__full_name", "suggestion__user__full_name", "submitter__email", "suggestion__user__username"] grouped_timeline = groupby( timeline.values(*timeline_fields), key=lambda x: ("%d\001%s" % (x['submitter_id'], x['creation_time']))) # Group by submitter id and creation_time because # different submissions can have same creation time for key, values in grouped_timeline: entry_group = { 'entries': [], } for item in values: # Only add creation_time information for the whole entry group once entry_group['datetime'] = item['creation_time'] # Only add submitter information for the whole entry group once entry_group.setdefault('submitter', ProxyTimelineUser(item)) context.setdefault( 'language', ProxyTimelineLanguage(item['translation_project__language__code'])) entry = { 'field': item['field'], 'field_name': SubmissionFields.NAMES_MAP.get(item['field'], None), 'type': item['type']} if item['field'] == SubmissionFields.STATE: entry['old_value'] = STATES_MAP[int(to_python(item['old_value']))] entry['new_value'] = STATES_MAP[int(to_python(item['new_value']))] elif item['suggestion_id']: entry.update({ 'suggestion_text': item['suggestion__target_f'], 'suggestion_description': mark_safe(_get_suggestion_description(item))}) elif item['quality_check__name']: check_name = item['quality_check__name'] check_url = ( u''.join( [reverse('pootle-checks-descriptions'), '#', check_name])) entry.update({ 'check_name': check_name, 'check_display_name': check_names[check_name], 'checks_url': check_url}) else: entry['new_value'] = to_python(item['new_value']) entry_group['entries'].append(entry) entries_group.append(entry_group) has_creation_entry = ( len(entries_group) > 0 and entries_group[0]['datetime'] == unit.creation_time) if (has_creation_entry): entries_group[0]['created'] = True else: created = { 'created': True, 'submitter': User.objects.get_system_user()} if unit.creation_time: created['datetime'] = unit.creation_time entries_group[:0] = [created] # Let's reverse the chronological order entries_group.reverse() context['entries_group'] = entries_group t = loader.get_template('editor/units/xhr_timeline.html') c = RequestContext(request, context) return t.render(c).replace('\n', '')
def base_entry(self): entry = self.entry_dict entry['new_value'] = to_python(self.submission.new_value) return entry
def get_submission_info(self): """Returns a dictionary describing the submission. The dict includes the user (with link to profile and gravatar), a type and translation_action_type describing the action performed, and when it was performed. """ result = {} if self.unit is not None: result.update({ 'unit_source': truncatechars(self.unit, 50), 'unit_url': self.unit.get_translate_url(), }) if self.quality_check is not None: check_name = self.quality_check.name result.update({ 'check_name': check_name, 'check_display_name': check_names.get(check_name, check_name), 'checks_url': reverse('pootle-checks-descriptions'), }) if (self.suggestion and self.type in (SubmissionTypes.SUGG_ACCEPT, SubmissionTypes.SUGG_REJECT)): displayuser = self.suggestion.reviewer else: # Sadly we may not have submitter information in all the # situations yet # TODO check if it is true if self.submitter: displayuser = self.submitter else: User = get_user_model() displayuser = User.objects.get_nobody_user() result.update({ "profile_url": displayuser.get_absolute_url(), "email": displayuser.email_hash, "displayname": displayuser.display_name, "username": displayuser.username, "display_datetime": dateformat.format(self.creation_time), "iso_datetime": self.creation_time.isoformat(), "type": self.type, "mtime": int(dateformat.format(self.creation_time, 'U')), }) #TODO Fix bug 3011 and remove the following code related # to TranslationActionTypes. if self.type in SubmissionTypes.EDIT_TYPES: translation_action_type = None try: if self.field == SubmissionFields.TARGET: if self.new_value != '': # Note that we analyze current unit state: # if this submission is not last unit state # can be changed if self.unit.state == TRANSLATED: if self.old_value == '': translation_action_type = \ TranslationActionTypes.TRANSLATED else: translation_action_type = \ TranslationActionTypes.EDITED elif self.unit.state == FUZZY: if self.old_value == '': translation_action_type = \ TranslationActionTypes.PRE_TRANSLATED else: translation_action_type = \ TranslationActionTypes.EDITED else: translation_action_type = TranslationActionTypes.REMOVED elif self.field == SubmissionFields.STATE: # Note that a submission where field is STATE # should be created before a submission where # field is TARGET translation_action_type = { TRANSLATED: TranslationActionTypes.REVIEWED, FUZZY: TranslationActionTypes.NEEDS_WORK }.get(int(to_python(self.new_value)), None) except AttributeError: return result result['translation_action_type'] = translation_action_type return result
def get_submission_message(self): """Returns a message describing the submission. The message includes the user (with link to profile and gravatar), a message describing the action performed, and when it was performed. """ unit = {} source = {} if self.unit is not None: unit = { 'source': escape(truncatechars(self.unit, 50)), 'url': self.unit.get_translate_url(), } source = { 'source_string': '<i><a href="%(url)s">%(source)s</a></i>' % unit, } if self.check is not None: unit.update({ 'check_name': self.check.name, 'check_display_name': check_names[self.check.name], 'checks_url': reverse('pootle-staticpages-display', args=['help/quality-checks']), }) source.update({ 'check_name': '<a href="%(checks_url)s#%(check_name)s">' '%(check_display_name)s</a>' % unit, }) if (self.suggestion and self.type in (SubmissionTypes.SUGG_ACCEPT, SubmissionTypes.SUGG_REJECT)): displayuser = self.suggestion.reviewer else: # Sadly we may not have submitter information in all the # situations yet # TODO check if it is true if self.submitter: displayuser = self.submitter else: User = get_user_model() displayuser = User.objects.get_nobody_user() displayname = displayuser.display_name action_bundle = { "profile_url": displayuser.get_absolute_url(), "gravatar_url": displayuser.gravatar_url(20), "displayname": displayname, "username": displayuser.username, "date": self.creation_time, "isoformat_date": self.creation_time.isoformat(), "action": "", } msg = { SubmissionTypes.REVERT: _('reverted translation for %(source_string)s', source), SubmissionTypes.SUGG_ACCEPT: _('accepted suggestion for %(source_string)s', source), SubmissionTypes.SUGG_ADD: _('added suggestion for %(source_string)s', source), SubmissionTypes.SUGG_REJECT: _('rejected suggestion for %(source_string)s', source), SubmissionTypes.UPLOAD: _('uploaded a file'), SubmissionTypes.MUTE_CHECK: _('muted %(check_name)s for %(source_string)s', source), SubmissionTypes.UNMUTE_CHECK: _('unmmuted %(check_name)s for %(source_string)s', source), }.get(self.type, None) #TODO Look how to detect submissions for "sent suggestion", "rejected # suggestion"... #TODO Fix bug 3011 and replace the following code with the appropiate # one in the dictionary above. if msg is None: try: if self.field == SubmissionFields.TARGET: if self.new_value != '': # Note that we analyze current unit state: # if this submission is not last unit state # can be changed if self.unit.state == TRANSLATED: if self.old_value == '': msg = _('translated %(source_string)s', source) else: msg = _('edited %(source_string)s', source) elif self.unit.state == FUZZY: if self.old_value == '': msg = _('pre-translated %(source_string)s', source) else: msg = _('edited %(source_string)s', source) else: msg = _('removed translation for %(source_string)s', source) elif self.field == SubmissionFields.STATE: # Note that a submission where field is STATE # should be created before a submission where # field is TARGET msg = { TRANSLATED: _('reviewed %(source_string)s', source), FUZZY: _('marked as fuzzy %(source_string)s', source) }.get(int(to_python(self.new_value)), '') else: msg = _('unknown action %(source_string)s', source) except AttributeError: return '' action_bundle['action'] = msg return mark_safe( u'<div class="last-action">' ' <a href="%(profile_url)s">' ' <img src="%(gravatar_url)s" />' ' <span title="%(username)s">%(displayname)s</span>' ' </a>' ' <span class="action-text">%(action)s</span>' ' <time class="extra-item-meta js-relative-date"' ' title="%(date)s" datetime="%(isoformat_date)s"> ' ' </time>' '</div>' % action_bundle)
def _calculate_timeline(request, unit): submission_filter = ( Q(field__in=[SubmissionFields.TARGET, SubmissionFields.STATE, SubmissionFields.COMMENT, SubmissionFields.NONE])) subs = ( Submission.objects.filter(unit=unit) .filter(submission_filter)) if unit.changed and unit.change.commented_on: subs = subs.exclude( field=SubmissionFields.COMMENT, creation_time=unit.commented_on) timeline = subs.order_by("id") User = get_user_model() entries_group = [] context = {} timeline_fields = [ "type", "old_value", "new_value", "submitter_id", "creation_time", "translation_project__language__code", "field", "suggestion_id", "suggestion__target_f", "quality_check__name", "submitter__username", "submitter__full_name", "suggestion__user__full_name", "submitter__email", "suggestion__user__username"] grouped_timeline = groupby( timeline.values(*timeline_fields), key=lambda item: "\001".join([ str(x) for x in [ item['submitter_id'], item['creation_time'], item['suggestion_id'], ] ]) ) # Group by submitter id and creation_time because # different submissions can have same creation time for key_, values in grouped_timeline: entry_group = { 'entries': [], } for item in values: # Only add creation_time information for the whole entry group once entry_group['datetime'] = item['creation_time'] # Only add submitter information for the whole entry group once entry_group.setdefault('submitter', ProxyTimelineUser(item)) context.setdefault( 'language', ProxyTimelineLanguage(item['translation_project__language__code'])) entry = { 'field': item['field'], 'field_name': SubmissionFields.NAMES_MAP.get(item['field'], None), 'type': item['type']} if item['field'] == SubmissionFields.STATE: entry['old_value'] = STATES_MAP[int(to_python(item['old_value']))] entry['new_value'] = STATES_MAP[int(to_python(item['new_value']))] elif item['suggestion_id']: entry.update({ 'suggestion_text': item['suggestion__target_f']}) elif item['quality_check__name']: check_name = item['quality_check__name'] check_url = ( u''.join( [reverse('pootle-checks-descriptions'), '#', check_name])) entry.update({ 'check_name': check_name, 'check_display_name': CHECK_NAMES[check_name], 'checks_url': check_url}) else: entry['new_value'] = to_python(item['new_value']) entry_group['entries'].append(entry) entries_group.append(entry_group) created = { 'created': True, 'submitter': User.objects.get_system_user()} if unit.creation_time: created['datetime'] = unit.creation_time entries_group[:0] = [created] # Let's reverse the chronological order entries_group.reverse() context['entries_group'] = entries_group t = loader.get_template('editor/units/xhr_timeline.html') return t.render(context=context, request=request)
def state_change_entry(self): entry = self.entry_dict entry['old_value'] = STATES_MAP[int(to_python(self.submission.old_value))] entry['new_value'] = STATES_MAP[int(to_python(self.submission.new_value))] return entry
def timeline(request, unit): """Returns a JSON-encoded string including the changes to the unit rendered in HTML. """ timeline = Submission.objects.filter(unit=unit, field__in=[ SubmissionFields.TARGET, SubmissionFields.STATE, SubmissionFields.COMMENT ]) timeline = timeline.select_related("submitter__user", "translation_project__language") context = {} entries_group = [] import locale from pootle_store.fields import to_python for key, values in groupby(timeline, key=lambda x: x.creation_time): entry_group = { 'datetime': key, 'datetime_str': key.strftime(locale.nl_langinfo(locale.D_T_FMT)), 'entries': [], } for item in values: # Only add submitter information for the whole entry group once entry_group.setdefault('submitter', item.submitter) context.setdefault('language', item.translation_project.language) entry = { 'field': item.field, 'field_name': SubmissionFields.NAMES_MAP[item.field], } if item.field == SubmissionFields.STATE: entry['old_value'] = STATES_MAP[int(to_python(item.old_value))] entry['new_value'] = STATES_MAP[int(to_python(item.new_value))] else: entry['new_value'] = to_python(item.new_value) entry_group['entries'].append(entry) entries_group.append(entry_group) # Let's reverse the chronological order entries_group.reverse() # Remove first timeline item if it's solely a change to the target if (entries_group and len(entries_group[0]['entries']) == 1 and entries_group[0]['entries'][0]['field'] == SubmissionFields.TARGET): del entries_group[0] context['entries_group'] = entries_group if request.is_ajax(): # The client will want to confirm that the response is relevant for # the unit on screen at the time of receiving this, so we add the uid. json = {'uid': unit.id} t = loader.get_template('unit/xhr-timeline.html') c = RequestContext(request, context) json['timeline'] = t.render(c).replace('\n', '') response = simplejson.dumps(json) return HttpResponse(response, mimetype="application/json") else: return render_to_response('unit/timeline.html', context, context_instance=RequestContext(request))
def _calculate_timeline(request, unit): submission_filter = Q( field__in=[ SubmissionFields.TARGET, SubmissionFields.STATE, SubmissionFields.COMMENT, SubmissionFields.NONE, ] ) | Q(type__in=SubmissionTypes.SUGGESTION_TYPES) timeline = ( Submission.objects.filter(unit=unit) .filter(submission_filter) .exclude(field=SubmissionFields.COMMENT, creation_time=unit.commented_on) .order_by("id") ) User = get_user_model() entries_group = [] context = {} timeline_fields = [ "type", "old_value", "new_value", "submitter_id", "creation_time", "translation_project__language__code", "field", "suggestion_id", "suggestion__target_f", "quality_check__name", "submitter__username", "submitter__full_name", "suggestion__user__full_name", "submitter__email", "suggestion__user__username", ] grouped_timeline = groupby( timeline.values(*timeline_fields), key=lambda item: "\001".join( [ str(x) for x in [ item["submitter_id"], item["creation_time"], item["suggestion_id"], ] ] ), ) # Group by submitter id and creation_time because # different submissions can have same creation time for key_, values in grouped_timeline: entry_group = { "entries": [], } for item in values: # Only add creation_time information for the whole entry group once entry_group["datetime"] = item["creation_time"] # Only add submitter information for the whole entry group once entry_group.setdefault("submitter", ProxyTimelineUser(item)) context.setdefault( "language", ProxyTimelineLanguage(item["translation_project__language__code"]), ) entry = { "field": item["field"], "field_name": SubmissionFields.NAMES_MAP.get(item["field"], None), "type": item["type"], } if item["field"] == SubmissionFields.STATE: entry["old_value"] = STATES_MAP[int(to_python(item["old_value"]))] entry["new_value"] = STATES_MAP[int(to_python(item["new_value"]))] elif item["suggestion_id"]: entry.update( { "suggestion_text": item["suggestion__target_f"], "suggestion_description": mark_safe( _get_suggestion_description(item) ), } ) elif item["quality_check__name"]: check_name = item["quality_check__name"] check_url = u"".join( [reverse("pootle-checks-descriptions"), "#", check_name] ) entry.update( { "check_name": check_name, "check_display_name": check_names[check_name], "checks_url": check_url, } ) else: entry["new_value"] = to_python(item["new_value"]) entry_group["entries"].append(entry) entries_group.append(entry_group) has_creation_entry = ( len(entries_group) > 0 and entries_group[0]["datetime"] == unit.creation_time ) if has_creation_entry: entries_group[0]["created"] = True else: created = {"created": True, "submitter": User.objects.get_system_user()} if unit.creation_time: created["datetime"] = unit.creation_time entries_group[:0] = [created] # Let's reverse the chronological order entries_group.reverse() context["entries_group"] = entries_group t = loader.get_template("editor/units/xhr_timeline.html") return t.render(context=context, request=request)
def get_submission_info(self): """Returns a dictionary describing the submission. The dict includes the user (with link to profile and gravatar), a type and translation_action_type describing the action performed, and when it was performed. """ result = {} if self.unit is not None: result.update({ 'source': truncatechars(self.unit, 50), 'uid': self.unit.id, }) if self.quality_check is not None: check_name = self.quality_check.name result.update({ 'check': check_name, 'check_displayname': check_names.get(check_name, check_name), }) if (self.suggestion and self.type in (SubmissionTypes.SUGG_ACCEPT, SubmissionTypes.SUGG_REJECT)): displayuser = self.suggestion.reviewer else: # Sadly we may not have submitter information in all the # situations yet # TODO check if it is true if self.submitter: displayuser = self.submitter else: User = get_user_model() displayuser = User.objects.get_nobody_user() result.update({ "email": displayuser.email_hash, "displayname": displayuser.display_name, "username": displayuser.username, "type": self.type, "mtime": int(dateformat.format(self.creation_time, 'U')), }) # TODO Fix bug 3011 and remove the following code related to # TranslationActionTypes. if self.type in SubmissionTypes.EDIT_TYPES: translation_action_type = None try: if self.field == SubmissionFields.TARGET: if self.new_value != '': # Note that we analyze current unit state: # if this submission is not last unit state # can be changed if self.unit.state == TRANSLATED: if self.old_value == '': translation_action_type = \ TranslationActionTypes.TRANSLATED else: translation_action_type = \ TranslationActionTypes.EDITED elif self.unit.state == FUZZY: if self.old_value == '': translation_action_type = \ TranslationActionTypes.PRE_TRANSLATED else: translation_action_type = \ TranslationActionTypes.EDITED else: translation_action_type = \ TranslationActionTypes.REMOVED elif self.field == SubmissionFields.STATE: # Note that a submission where field is STATE # should be created before a submission where # field is TARGET translation_action_type = { TRANSLATED: TranslationActionTypes.REVIEWED, FUZZY: TranslationActionTypes.NEEDS_WORK }.get(int(to_python(self.new_value)), None) except AttributeError: return result result['translation_action_type'] = translation_action_type return result
def context(self): return dict(value=format_html( u"{} <span class='timeline-arrow'></span> {}", STATES_MAP[int(to_python(self.submission.old_value))], STATES_MAP[int(to_python(self.submission.new_value))]), state=True)