From e80a1dfbdb62335d31815eb7ddc239dc00cda418 Mon Sep 17 00:00:00 2001 From: zhengxie Date: Thu, 29 Jan 2015 14:45:26 +0800 Subject: [PATCH] Show group recent changes --- .../scripts/app/collections/group-changes.js | 19 ++++ media/scripts/app/models/group-change.js | 10 ++ media/scripts/app/routers/group.js | 14 ++- media/scripts/app/views/group-change-items.js | 81 ++++++++++++++++ .../scripts/app/views/group-recent-change.js | 94 +++++++++++++++++++ media/scripts/app/views/group.js | 18 +++- media/scripts/common.js | 9 +- seahub/api2/urls.py | 1 + seahub/api2/views.py | 68 +++++++++++++- seahub/group/templates/group/group_info.html | 70 ++++---------- seahub/templates/js/group-change-item.html | 13 +++ 11 files changed, 339 insertions(+), 58 deletions(-) create mode 100644 media/scripts/app/collections/group-changes.js create mode 100644 media/scripts/app/models/group-change.js create mode 100644 media/scripts/app/views/group-change-items.js create mode 100644 media/scripts/app/views/group-recent-change.js create mode 100644 seahub/templates/js/group-change-item.html diff --git a/media/scripts/app/collections/group-changes.js b/media/scripts/app/collections/group-changes.js new file mode 100644 index 0000000000..59742ca424 --- /dev/null +++ b/media/scripts/app/collections/group-changes.js @@ -0,0 +1,19 @@ +define([ + 'underscore', + 'backbone', + 'app/models/group-change' +], function(_, Backbone, GroupChange) { + 'use strict'; + + var GroupChangeCollection = Backbone.Collection.extend({ + model: GroupChange, + url: app.pageOptions.groupChangesUrl, + + initialize: function() { + + } + + }); + + return new GroupChangeCollection(); +}); diff --git a/media/scripts/app/models/group-change.js b/media/scripts/app/models/group-change.js new file mode 100644 index 0000000000..65be18fd8d --- /dev/null +++ b/media/scripts/app/models/group-change.js @@ -0,0 +1,10 @@ +define([ + 'underscore', + 'backbone' +], function(_, Backbone) { + 'use strict'; + + var GroupChange = Backbone.Model.extend({}); + + return GroupChange; +}); diff --git a/media/scripts/app/routers/group.js b/media/scripts/app/routers/group.js index 9f33046bee..e558e46bff 100644 --- a/media/scripts/app/routers/group.js +++ b/media/scripts/app/routers/group.js @@ -11,20 +11,30 @@ define([ routes: { 'libs/:id(/*path)': 'showDirents', + 'recent-changes': 'showRecentChanges', + // Default '*actions': 'defaultAction' }, + initialize: function() { + this.groupView = new GroupView(); + }, + showDirents: function(id, path){ console.log("Repo route has been called.." + "id:" + id + " path:" + path); // new GroupView().showDirentList(id, path); }, + showRecentChanges: function() { + console.log('recent changes'); + this.groupView.showChanges(); + }, + defaultAction: function(actions){ // We have no matching route, lets just log what the URL was console.log('No route:', actions); - - new GroupView().showRepoList(); + this.groupView.showRepoList(); } }); diff --git a/media/scripts/app/views/group-change-items.js b/media/scripts/app/views/group-change-items.js new file mode 100644 index 0000000000..74518780a0 --- /dev/null +++ b/media/scripts/app/views/group-change-items.js @@ -0,0 +1,81 @@ +define([ + 'jquery', + 'underscore', + 'backbone', + 'common', + 'text!' + app.config._tmplRoot + 'group-change-item.html' +], function($, _, Backbone, Common, changeItemTemplate) { + 'use strict'; + + var GroupChangeItemView = Backbone.View.extend({ + tagName: 'tr', + + template: _.template(changeItemTemplate), + + events: { + 'click .lsch': 'showDetail' + }, + + render: function() { + this.$el.html(this.template(this.model.toJSON())); + return this; + }, + + showDetail: function() { + console.log(this.model); + + // TODO: if repo is encrypted, and not set password, show decrypt + // form, else show details + + var model = this.model; + var url = app.config.siteRoot + 'ajax/repo/' + model.get("repo").id + '/history/changes/' + "?commit_id=" + model.get("id"); + var loadingHtml = '
'; + $.modal(loadingHtml, {autoResize:true}); + $('#ls-ch').css('text-align', 'center'); + $('#simplemodal-container').css({'width':'auto', 'height':'auto'}); + $.ajax({ + url: url, + dataType: 'json', + cache: false, + success: function(data) { + var heading = '

' + "Modification Details" + '

'; + var time = '

' + model.get("ctime") + '

'; + var con = ''; + function show(data_, hd) { + if (data_.length > 0) { + con += '

' + hd + '

'; + con += ''; + } + } + show(data['new'], "New files"); + show(data['removed'], "Deleted files"); + show(data['renamed'], "Renamed or Moved files"); + show(data['modified'], "Modified files"); + show(data['newdir'], "New directories"); + show(data['deldir'], "Deleted directories"); + if (!con) { + if (data['cmt_desc']) { + con = '

' + Common.HTMLescape(data['cmt_desc']) + '

'; + } + } + $('#ls-ch').css('text-align','left').html(heading + time + con); + $(window).resize(); + }, + error: function() { + $('#ls-ch').html("Unknown error."); + setTimeout(function() { $.modal.close(); }, 2500); + } + }); + + + + + } + }); + + return GroupChangeItemView; +}); diff --git a/media/scripts/app/views/group-recent-change.js b/media/scripts/app/views/group-recent-change.js new file mode 100644 index 0000000000..878b3fdd1b --- /dev/null +++ b/media/scripts/app/views/group-recent-change.js @@ -0,0 +1,94 @@ +define([ + 'jquery', + 'underscore', + 'backbone', + 'common', + 'app/collections/group-changes', + 'app/views/group-change-items' +], function($, _, Backbone, Common, RecentChanges, GroupChangeItemView) { + 'use strict'; + + var GroupRecentChangeView = Backbone.View.extend({ + el: '#grp-repos-commits', + + initialize: function() { + this.$cont = this.$el; + this.$table = $('table', this.$el); + this.$tableHead = $('thead', this.$table); + this.$tableBody = $('tbody', this.$table); + + this.listenTo(RecentChanges, 'add', this.addOne); + this.listenTo(RecentChanges, 'reset', this.addAll); + this.listenTo(RecentChanges, 'error', this.error); + this.listenTo(RecentChanges, 'all', this.render); // XXX: really render table when recieve any event ? + + }, + + error: function(model_or_collection, resp, options) { + Common.feedback(resp.statusText, "error", Common.ERROR_TIMEOUT); + }, + + all: function(event) { + console.log('event: ' + event); + }, + + addOne: function(change, collection, options) { + console.log('add one change'); + var view = new GroupChangeItemView({model: change}); + if (options.prepend) { + this.$tableBody.before(view.render().el); + } else { + this.$tableBody.append(view.render().el); + } + }, + + addAll: function() { + console.log('add all'); + this.resetTable(); + RecentChanges.each(this.addOne, this); + }, + + // Reset table by empty table body. + resetTable: function() { + console.log('reset table'); + this.$tableBody.empty(); + }, + + show: function() { + RecentChanges.fetch({reset: true}); + }, + + render: function(event) { + console.log('got event: ' + event + ', render change list...' ); + + this.$table.parent().show(); + this.hideLoading(); + + if (RecentChanges.length) { + this.showTable(); + } else { + this.hideTable(); + } + + }, + + hideTable: function() { + this.$table.hide(); + }, + + showTable: function() { + this.$table.show(); + }, + + hideLoading: function() { + this.$cont.find('.loading').hide(); + }, + + showLoading: function() { + this.$cont.find('.loading').show(); + }, + + }); + + return GroupRecentChangeView; +}); diff --git a/media/scripts/app/views/group.js b/media/scripts/app/views/group.js index ff9de2d357..f6fceb8be5 100644 --- a/media/scripts/app/views/group.js +++ b/media/scripts/app/views/group.js @@ -6,9 +6,10 @@ define([ 'app/collections/group-repos', 'app/collections/dirents', 'app/views/group-repos', - 'app/views/add-group-repo' + 'app/views/add-group-repo', + 'app/views/group-recent-change' // 'app/views/dirents' -], function($, _, Backbone, Common, Repos, DirentCollection, GroupRepoView, AddGroupRepoView/*, DirentView*/) { +], function($, _, Backbone, Common, Repos, DirentCollection, GroupRepoView, AddGroupRepoView/*, DirentView*/, GroupRecentChangeView) { 'use strict'; var GroupView = Backbone.View.extend({ @@ -24,7 +25,6 @@ define([ this.$cont = this.$('#right-panel'); this.$tab = this.$('#tabs div:first-child'); - this.$tabCont = this.$('#grp-repos'); this.$table = this.$('#grp-repos table'); this.$tableHead = $('thead', this.$table); @@ -38,6 +38,7 @@ define([ this.listenTo(Repos, 'reset', this.addAll); // this.listenTo(Repos, 'sync', this.render); this.listenTo(Repos, 'all', this.render); // XXX: really render table when recieve any event ? + this.listenTo(Repos, 'all', this.all); }, all: function(event) { @@ -93,7 +94,9 @@ define([ render: function(event) { console.log('got event: ' + event + ', render repo list...' ); + this.$table.parent().show(); this.hideLoading(); + if (Repos.length) { this.hideEmptyTips(); this.showTable(); @@ -110,6 +113,15 @@ define([ createRepo: function() { new AddGroupRepoView(); + }, + + showChanges: function() { + this.$table.parent().hide(); // XXX: hide or empty ? + + if (!this.recentChangeView) { + this.recentChangeView = new GroupRecentChangeView(); + } + this.recentChangeView.show(); } }); diff --git a/media/scripts/common.js b/media/scripts/common.js index 5fb7530e3e..53f209223d 100644 --- a/media/scripts/common.js +++ b/media/scripts/common.js @@ -207,6 +207,13 @@ define([ }); }, + HTMLescape: function(html){ + return document.createElement('div') + .appendChild(document.createTextNode(html)) + .parentNode + .innerHTML; + }, + pathJoin: function(array) { var result = array[0]; for (var i = 1; i < array.length; i++) { @@ -216,7 +223,7 @@ define([ result += '/' + array[i]; } return result; - }, + } } }); diff --git a/seahub/api2/urls.py b/seahub/api2/urls.py index 0ebf509b23..da7b8f7eeb 100644 --- a/seahub/api2/urls.py +++ b/seahub/api2/urls.py @@ -70,6 +70,7 @@ urlpatterns = patterns('', url(r'^groups/$', Groups.as_view()), url(r'^groups/(?P\d+)/$', Groups.as_view()), url(r'^groups/(?P\d+)/members/$', GroupMembers.as_view()), + url(r'^groups/(?P\d+)/changes/$', GroupChanges.as_view(), name="api2-group-changes"), url(r'^groups/(?P\d+)/repos/$', GroupRepos.as_view(), name="api2-grouprepos"), url(r'^groups/(?P\d+)/repos/(?P[-0-9a-f]{36})/$', GroupRepo.as_view()), diff --git a/seahub/api2/views.py b/seahub/api2/views.py index deccb554de..e0c58d59c9 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -44,7 +44,8 @@ from seahub.avatar.templatetags.group_avatar_tags import api_grp_avatar_url, \ grp_avatar from seahub.base.accounts import User from seahub.base.models import FileDiscuss, UserStarredFiles, DeviceToken -from seahub.base.templatetags.seahub_tags import email2nickname +from seahub.base.templatetags.seahub_tags import email2nickname, \ + translate_commit_desc, translate_seahub_time from seahub.group.models import GroupMessage, MessageReply, MessageAttachment from seahub.group.signals import grpmsg_added, grpmsg_reply_added from seahub.group.views import group_check, remove_group_common, \ @@ -2856,6 +2857,71 @@ class GroupMembers(APIView): return HttpResponse(json.dumps({'success': True}), status=200, content_type=json_content_type) +class GroupChanges(APIView): + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated,) + throttle_classes = (UserRateThrottle, ) + + def get(self, request, group_id, format=None): + # TODO: group check + + # TODO: perm check + + group_id = int(group_id) + username = request.user.username + if is_org_context(request): + org_id = request.user.org.org_id + repos = seaserv.get_org_group_repos(org_id, group_id, username) + else: + repos = seaserv.get_group_repos(group_id, username) + + recent_commits = [] + cmt_repo_dict = {} + for repo in repos: + repo.user_perm = check_permission(repo.props.id, username) + cmmts = get_commits(repo.props.id, 0, 10) + for c in cmmts: + cmt_repo_dict[c.id] = repo + recent_commits += cmmts + + recent_commits.sort(lambda x, y: cmp(y.props.ctime, x.props.ctime)) + recent_commits = recent_commits[:15] + for cmt in recent_commits: + cmt.repo = cmt_repo_dict[cmt.id] + cmt.repo.password_set = is_passwd_set(cmt.props.repo_id, username) + cmt.tp = cmt.props.desc.split(' ')[0] + + res = [] + for c in recent_commits: + cmt_tp = c.tp.lower() + if 'add' in cmt_tp: + change_tp = 'added' + elif ('delete' or 'remove') in cmt_tp: + change_tp = 'deleted' + else: + change_tp = 'modified' + + change_repo = { + 'id': c.repo.id, + 'name': c.repo.name, + 'desc': c.repo.desc, + 'encrypted': c.repo.encrypted, + } + change = { + "type": change_tp, + "repo": change_repo, + "id": c.id, + "desc": c.desc, + "desc_human": translate_commit_desc(c.desc), + "ctime": c.ctime, + "ctime_human": translate_seahub_time(c.ctime), + "creator": c.creator_name, + "creator_nickname": email2nickname(c.creator_name) + } + res.append(change) + + return Response(res) + class GroupRepos(APIView): authentication_classes = (TokenAuthentication, SessionAuthentication) permission_classes = (IsAuthenticated,) diff --git a/seahub/group/templates/group/group_info.html b/seahub/group/templates/group/group_info.html index 6df68c9f95..40f0bb48b6 100644 --- a/seahub/group/templates/group/group_info.html +++ b/seahub/group/templates/group/group_info.html @@ -65,16 +65,18 @@
{% if user.permissions.can_add_repo %} {% endif %}
+ + +

{% trans "Loading ..." %}

- @@ -97,54 +99,19 @@
- {% if recent_commits|length > 0 %} -
- - - - - - - - - {% for cmt in recent_commits %} - - - - - - - - {% endfor %} -
{% trans "Library" %}{% trans "Description" %}{% trans "Modified at" %}{% trans "Modifier" %}
- {% if cmt.tp == 'Added' or cmt.tp == 'Deleted' or cmt.tp == 'Removed' %} - {% if cmt.tp == 'Added' %} - - {% else %} - - {% endif %} - {% else %} - - {% endif %} - {{ cmt.repo.props.name }} - {{cmt.props.desc|translate_commit_desc}} - {% if cmt.repo.encrypted %} - {% trans 'Details' %} - {% else %} - {% trans 'Details' %} - {% endif %} - {{cmt.props.ctime|translate_seahub_time}} - {% if cmt.creator_name %} - {% if cmt.second_parent_id %} - {% trans "None" %} - {% else %} - {{cmt.creator_name|email2nickname}} - {% endif %} - {% else %} - {% trans "Unknown"%} - {% endif %} -
- {% endif %} +

{% trans "Loading ..." %}

+ + + + + + + + + + + +
{% trans "Library" %}{% trans "Description" %}{% trans "Modified at" %}{% trans "Modifier" %}
@@ -170,6 +137,7 @@ app["pageOptions"] = { groupId: {{ group.id }}, groupReposUrl: "{% url "api2-grouprepos" group.id %}", + groupChangesUrl: "{% url "api2-group-changes" group.id %}", isGroupStaff: (function() { if ("{{ is_staff }}" == "True") return true; diff --git a/seahub/templates/js/group-change-item.html b/seahub/templates/js/group-change-item.html new file mode 100644 index 0000000000..2b127fe3e2 --- /dev/null +++ b/seahub/templates/js/group-change-item.html @@ -0,0 +1,13 @@ +{% load i18n %} + + + +<%= repo.name %> + + <%= desc_human %> + {% trans 'Details' %} + +<%= ctime_human %> + + <%- creator_nickname %> +