1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-02 07:47:32 +00:00

add text file diff

This commit is contained in:
lins05 2012-10-16 14:47:36 +08:00
parent 1f08f9fb52
commit f9e0437628
10 changed files with 2216 additions and 12 deletions

View File

@ -44,6 +44,7 @@ class FileContributors(models.Model):
file_path_hash = models.CharField(max_length=12)
last_modified = models.BigIntegerField()
last_commit_id = models.CharField(max_length=40)
# email addresses seperated by comma
emails = models.TextField()

View File

@ -928,7 +928,7 @@ ul.with-bg li {
color:#666;
margin-left:5px;
}
.lsch, .lsch-encrypted {
.lsch, .lsch-encrypted, .file-diff {
font-size:12px;
font-weight:normal;
color:#666;
@ -1378,3 +1378,16 @@ ul.with-bg li {
}
.placeholder { color: #aaa; }
/* text file diff */
div.diff-desc { margin: 10px 0; }
div.diff-desc p { margin: 10px 0; }
#text-diff-output table { margin-top: 20px; border: 1px solid gray; }
#text-diff-output thead { border: 1px solid gray; }
#text-diff-output th { background-color: #EED; text-align: center; }
#text-diff-output th, #text-diff-output td { border-bottom: none; }
#text-diff-output tr.hl { background-color: #afcde8; }/*highlight*/
.diff_header { background-color: #EED; text-align: center; }
.diff_add { background-color: #DFD; }
.diff_sub { background-color: #FDD; }
.diff_chg { background-color: #FD8; }

View File

@ -82,7 +82,13 @@
{% if not view_history %}
<div id="file-commit-info">
<div class="latest-commit ovhd">
<p class="latest-commit-info fleft">{% avatar latest_contributor 20 %} <a href="{% url 'user_profile' latest_contributor %}" class="name">{{ latest_contributor|email2nickname }}</a> <span class="time">{{ last_modified|translate_commit_time}}</span><span> 做了最新修改</span></p>
<p class="latest-commit-info fleft">{% avatar latest_contributor 20 %} <a href="{% url 'user_profile' latest_contributor %}" class="name">{{ latest_contributor|email2nickname }}</a> <span class="time">{{ last_modified|translate_commit_time}}</span><span> 做了最新修改</span>
{% if filetype == 'Text' or filetype == 'Markdown' %}
{% if last_commit_id %}
<span><a class="file-diff" href="{% url 'text_diff' repo.id %}?p={{path|urlencode}}&commit={{last_commit_id}}">详情</a></span>
{% endif %}
{% endif %}
</p>
<a href="{{ SITE_ROOT }}repo/file_revisions/{{ repo.id }}/?p={{ path }}" class="more fright">更多历史</a>
</div>
<p class="contributors">

View File

@ -14,3 +14,6 @@
{% if filetype == 'Markdown' %}
<script type="text/javascript" src="{{MEDIA_URL}}js/showdown.js"></script>
{% endif %}
{% if filetype == 'Text' or filetype == 'Markdown' %}
{% endif %}

39
templates/text_diff.html Normal file
View File

@ -0,0 +1,39 @@
{% extends base_template %}
{% load seahub_tags avatar_tags%}
{% load url from future %}
{% block main_panel %}
<h2>文件修改详情</h2>
<div class="diff-desc">
<p class="path">
文件路径:
{% for name, link in zipped %}
{% if not forloop.last %}
<a href="{% url 'repo' repo.id %}?p={{ link|urlencode }}">{{ name }}</a> /
{% else %}
<a href="{% url 'repo_view_file' repo.id %}?p={{ link|urlencode }}">{{ name }}</a>
{% endif %}
{% endfor %}
</p>
<p class="">{% avatar current_commit.creator_name 20 %} {{ current_commit.creator_name|email2nickname }} 修改于 {{ current_commit.ctime|translate_commit_time }}</p>
</div>
{% if is_new_file %}
<div class="text-panel">
<p>文件 {{repo.name}} {{ path }} 是一个新建的空白文件</p>
</div>
{% else %}
<div id="text-diff-output">
<table rules="group">
<thead>
<th width="3%"></th>
<th width="47%"> 修改前 </th>
<th width="3%"></th>
<th width="47%"> 修改后 </th>
</thead>
<tbody>
{{ diff_result_table|safe }}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}

View File

@ -28,3 +28,5 @@ from service import get_related_users_by_repo, get_related_users_by_org_repo
from service import CCNET_CONF_PATH, CCNET_SERVER_ADDR, CCNET_SERVER_PORT
from htmldiff import HtmlDiff

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,7 @@ urlpatterns = patterns('',
(r'^repo/upload_error/(?P<repo_id>[^/]+)/$', upload_file_error),
(r'^repo/update_error/(?P<repo_id>[^/]+)/$', update_file_error),
url(r'^repo/file_revisions/(?P<repo_id>[^/]+)/$', file_revisions, name='file_revisions'),
url(r'^repo/text_diff/(?P<repo_id>[^/]+)/$', text_diff, name='text_diff'),
url(r'^repo/(?P<repo_id>[^/]{36,36})/$', RepoView.as_view(), name='repo'),
(r'^repo/history/(?P<repo_id>[^/]+)/$', repo_history),
(r'^repo/history/revert/(?P<repo_id>[^/]+)/$', repo_history_revert),

View File

@ -367,7 +367,7 @@ def get_file_contributors_from_revisions(repo_id, file_path):
if user not in ret:
ret.append(user)
return ret, commits[0].ctime
return ret, commits[0].ctime, commits[0].id
def get_file_contributors(repo_id, file_path, file_path_hash, file_id):
"""Get file contributors list and last modfied time from database cache.
@ -376,12 +376,13 @@ def get_file_contributors(repo_id, file_path, file_path_hash, file_id):
"""
contributors = []
last_modified = 0
last_commit_id = ''
try:
fc = FileContributors.objects.get(repo_id=repo_id,
file_path_hash=file_path_hash)
except FileContributors.DoesNotExist:
# has no cache yet
contributors, last_modified = get_file_contributors_from_revisions (repo_id, file_path)
contributors, last_modified, last_commit_id = get_file_contributors_from_revisions (repo_id, file_path)
if not contributors:
return [], 0
emails = ','.join(contributors)
@ -390,22 +391,24 @@ def get_file_contributors(repo_id, file_path, file_path_hash, file_id):
file_path=file_path,
file_path_hash=file_path_hash,
last_modified=last_modified,
last_commit_id=last_commit_id,
emails=emails)
file_contributors.save()
else:
# cache found
if fc.file_id != file_id:
if fc.file_id != file_id or not fc.last_commit_id:
# but cache is outdated
fc.delete()
contributors, last_modified = get_file_contributors_from_revisions (repo_id, file_path)
contributors, last_modified, last_commit_id = get_file_contributors_from_revisions (repo_id, file_path)
if not contributors:
return [], 0
return [], 0, ''
emails = ','.join(contributors)
file_contributors = FileContributors(repo_id=repo_id,
file_id=file_id,
file_path=file_path,
file_path_hash=file_path_hash,
last_modified=last_modified,
last_commit_id=last_commit_id,
emails=emails)
file_contributors.save()
else:
@ -415,8 +418,9 @@ def get_file_contributors(repo_id, file_path, file_path_hash, file_id):
else:
contributors = []
last_modified = fc.last_modified
last_commit_id = fc.last_commit_id
return contributors, last_modified
return contributors, last_modified, last_commit_id
if hasattr(settings, 'EVENTS_CONFIG_FILE'):

View File

@ -42,7 +42,7 @@ from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_repos, get_emailusers, \
list_personal_shared_repos, is_org_group, get_org_id_by_group, is_org_repo,\
list_inner_pub_repos, get_org_groups_by_repo, is_org_repo_owner, \
get_org_repo_owner, is_passwd_set, get_file_size, \
get_related_users_by_repo, get_related_users_by_org_repo
get_related_users_by_repo, get_related_users_by_org_repo, HtmlDiff
from pysearpc import SearpcError
from signals import repo_created, repo_deleted
@ -77,7 +77,6 @@ except ImportError:
DOCUMENT_CONVERTOR_ROOT = None
from settings import FILE_PREVIEW_MAX_SIZE, INIT_PASSWD
@login_required
def root(request):
return HttpResponseRedirect(reverse(myhome))
@ -786,7 +785,7 @@ def repo_history_changes(request, repo_id):
return HttpResponse(json.dumps(changes),
content_type=content_type)
@login_required
def modify_token(request, repo_id):
if not validate_owner(request, repo_id):
@ -1290,7 +1289,7 @@ def repo_view_file(request, repo_id):
file_path_hash = md5_constructor(urllib2.quote(path.encode('utf-8'))).hexdigest()[:12]
comments = FileComment.objects.filter(file_path_hash=file_path_hash, repo_id=repo_id)
contributors, last_modified = get_file_contributors(repo_id, path.encode('utf-8'), file_path_hash, obj_id)
contributors, last_modified, last_commit_id = get_file_contributors(repo_id, path.encode('utf-8'), file_path_hash, obj_id)
latest_contributor = contributors[0]
return render_to_response('repo_view_file.html', {
@ -1323,6 +1322,7 @@ def repo_view_file(request, repo_id):
'contributors': contributors,
'latest_contributor': latest_contributor,
'last_modified': last_modified,
'last_commit_id': last_commit_id,
'read_only': read_only,
'page_from': page_from,
}, context_instance=RequestContext(request))
@ -2610,3 +2610,86 @@ def repo_set_password(request):
return HttpResponse(json.dumps(ret),
content_type=content_type)
def get_file_content_by_commit_and_path(request, repo_id, commit_id, path):
try:
obj_id = seafserv_threaded_rpc.get_file_id_by_commit_and_path( \
commit_id, path)
except:
return None, 'bad path'
if not obj_id or obj_id == EMPTY_SHA1:
return '', None
else:
permission = get_user_permission(request, repo_id)
if permission:
# Get a token to visit file
token = seafserv_rpc.web_get_access_token(repo_id,
obj_id,
'view',
request.user.username)
else:
return None, 'permission denied'
filename = os.path.basename(path)
raw_path = gen_file_get_url(token, urllib2.quote(filename))
try:
err, file_content, encoding, newline_mode = repo_file_get(raw_path)
except Exception, e:
return None, 'error when read file from httpserver: %s' % e
return file_content, err
@login_required
def text_diff(request, repo_id):
commit_id = request.GET.get('commit', '')
path = request.GET.get('p', '')
if not (commit_id and path):
return render_error(request, 'bad params')
repo = get_repo(repo_id)
if not repo:
return render_error(request, 'bad repo')
current_commit = seafserv_threaded_rpc.get_commit(commit_id)
if not current_commit:
return render_error(request, 'bad commit id')
prev_commit = seafserv_threaded_rpc.get_commit(current_commit.parent_id)
if not prev_commit:
return render_error('bad commit id')
path = path.encode('utf-8')
current_content, err = get_file_content_by_commit_and_path(request, \
repo_id, current_commit.id, path)
if err:
return render_error(request, err)
prev_content, err = get_file_content_by_commit_and_path(request, \
repo_id, prev_commit.id, path)
if err:
return render_error(request, err)
is_new_file = False
diff_result_table = ''
if prev_content == '' and current_content == '':
is_new_file = True
else:
diff = HtmlDiff()
diff_result_table = diff.make_table(prev_content.splitlines(),
current_content.splitlines())
zipped = gen_path_link(path, repo.name)
return render_to_response('text_diff.html', {
'repo': repo,
'path': path,
'zipped': zipped,
'current_commit': current_commit,
'prev_commit': prev_commit,
'diff_result_table': diff_result_table,
'is_new_file': is_new_file,
}, context_instance=RequestContext(request))