1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-03 07:55:36 +00:00

add search results highlight

This commit is contained in:
lins05
2013-03-09 14:15:53 +08:00
parent 2bb4532fb9
commit d4525e2845
7 changed files with 188 additions and 59 deletions

View File

@@ -13,6 +13,11 @@ try:
except ImportError: except ImportError:
BUSINESS_MODE = False BUSINESS_MODE = False
try:
from settings import ENABLE_FILE_SEARCH
except ImportError:
ENABLE_FILE_SEARCH = False
def base(request): def base(request):
""" """
Add seahub base configure to the context. Add seahub base configure to the context.
@@ -37,5 +42,6 @@ def base(request):
'site_name': SITE_NAME, 'site_name': SITE_NAME,
'enable_signup': ENABLE_SIGNUP, 'enable_signup': ENABLE_SIGNUP,
'max_file_name': MAX_FILE_NAME, 'max_file_name': MAX_FILE_NAME,
'enable_file_search': ENABLE_FILE_SEARCH,
} }

View File

@@ -181,4 +181,17 @@ class DirFilesLastModifiedInfo(models.Model):
last_modified_info = models.TextField() last_modified_info = models.TextField()
class Meta: class Meta:
unique_together = ('repo_id', 'parent_dir_hash') unique_together = ('repo_id', 'parent_dir_hash')
class FileLastModifiedInfo(models.Model):
repo_id = models.CharField(max_length=36, db_index=True)
file_id = models.CharField(max_length=40)
file_path = models.TextField()
file_path_hash = models.CharField(max_length=12)
last_modified = models.BigIntegerField()
email = models.EmailField()
class Meta:
unique_together = ('repo_id', 'file_path_hash')

View File

@@ -1971,6 +1971,41 @@ textarea:-moz-placeholder {/* for FF */
background:#f7f7f8; background:#f7f7f8;
border-radius:2px; border-radius:2px;
} }
#search-results { #search-results {
padding-top:15px; padding-top:15px;
}
#search-results a {
font-weight: normal;
}
#search-results b {
font-weight: bold;
}
.search-results-item {
margin-top: 20px;
clear: left;
}
.search-results-item .file-icon {
display: block;
float: left;
}
.search-results-item .title {
margin: 0 0 0 40px;
}
.search-results-item .title a,
.search-results-item .title img,
.search-results-item .title span
{
vertical-align: middle;
}
.search-results-item .content {
clear: left;
margin: 0 0 0 40px;
} }

View File

@@ -87,7 +87,7 @@
</a> </a>
{% block nav %}{% endblock %} {% block nav %}{% endblock %}
{% if request.user.is_authenticated %} {% if enable_file_search and request.user.is_authenticated %}
<form id="top-search-form" method="get" action="{% url 'search' %}" class="search-form fright"> <form id="top-search-form" method="get" action="{% url 'search' %}" class="search-form fright">
<input class="search-input" name="q" placeholder="{% trans 'Search Files' %}" value="{{ keyword }}" /> <input class="search-input" name="q" placeholder="{% trans 'Search Files' %}" value="{{ keyword }}" />
<input type="submit" value="" class="search-submit" /> <input type="submit" value="" class="search-submit" />

View File

@@ -16,26 +16,39 @@
<p>{% trans 'No result found' %}</p> <p>{% trans 'No result found' %}</p>
{% else %} {% else %}
<p class="tip">{% blocktrans count counter=total %}{{ total }} result{% plural %}{{ total }} results{% endblocktrans%}</p> <p class="tip">{% blocktrans count counter=total %}{{ total }} result{% plural %}{{ total }} results{% endblocktrans%}</p>
<table> <ul id="search-results-list">
<tr> {% for file in results %}
<th width="5%"></th> <li class="search-results-item">
<th width="45%">{% trans 'Name' %}</th> <img class="file-icon" src="{{ MEDIA_URL }}img/file/{{ file.name|file_icon_filter }}" alt="{% trans "File"%}" />
<th width="22%">{% trans 'Library' %}</th> <div class="title">
<th width="28%">{% trans 'Owner' %}</th> <a href="{% url 'repo' repo_id=file.repo.id %}" target="_blank">{{ file.repo.name }}</a>
</tr> <span></span>
{% for file in results %} <a class="filename" href="{% url 'repo_view_file' repo_id=file.repo.id %}?p={{ file.fullpath|urlencode }}" target="_blank" title="{{ file.fullpath|slice:'1:'}}" >
<tr> {% if file.name_highlight %}
<td><img src="{{ MEDIA_URL }}img/file/{{ file.name|file_icon_filter }}" alt="{% trans "File"%}" /></td> {{ file.name_highlight|safe }}
<td><a href="{% url 'repo_view_file' repo_id=file.repo.id %}?p={{ file.fullpath|urlencode }}" target="_blank">{{ file.name }}</a></td> {% else %}
<td><a href="{% url 'repo' repo_id=file.repo.id %}" target="_blank">{{ file.repo.name }}</a></td> {{ file.name }}
<td> {% endif %}
{% avatar file.repo.owner 20 %} </a>
<a class="name" href="{% url 'profile.views.user_profile' file.repo.owner %}" target="_blank">{{ file.repo.owner|email2nickname }}</a> <p>
</td> {% if file.last_modified_by %}
</tr> {% avatar file.last_modified_by 20 %}
{% endfor %} <a class="name" href="{% url 'profile.views.user_profile' file.last_modified_by %}">{{ file.last_modified_by|email2nickname }}</a>
</table> {% endif %}
{% if total > 25 %} {% if file.last_modified %}
{{ file.last_modified|translate_seahub_time }}
{% endif %}
</p>
</div>
{% if file.content_highlight %}
<div class="content">
{{ file.content_highlight|safe }}
</div>
{% endif %}
</li>
{% endfor %}
</ul>
{% if total > per_page %}
<div id="paginator"> <div id="paginator">
{% if current_page != 1 %} {% if current_page != 1 %}
<a href="?q={{ keyword|urlencode }}&page={{ prev_page }}&per_page={{ per_page }}">{% trans "Previous"%}</a> <a href="?q={{ keyword|urlencode }}&page={{ prev_page }}&per_page={{ per_page }}">{% trans "Previous"%}</a>

View File

@@ -103,7 +103,6 @@ urlpatterns = patterns('',
url(r'^sys/orgadmin/$', sys_org_admin, name='sys_org_admin'), url(r'^sys/orgadmin/$', sys_org_admin, name='sys_org_admin'),
url(r'^sys/groupadmin/$', sys_group_admin, name='sys_group_admin'), url(r'^sys/groupadmin/$', sys_group_admin, name='sys_group_admin'),
url(r'^search/$', search, name='search'),
) )
if settings.SERVE_STATIC: if settings.SERVE_STATIC:
@@ -128,3 +127,8 @@ else:
url(r'^pubinfo/groups/$', pubgrp, name='pubgrp'), url(r'^pubinfo/groups/$', pubgrp, name='pubgrp'),
url(r'^pubinfo/users/$', pubuser, name='pubuser'), url(r'^pubinfo/users/$', pubuser, name='pubuser'),
) )
if getattr(settings, 'ENABLE_FILE_SEARCH', False):
urlpatterns += patterns('',
url(r'^search/$', search, name='search'),
)

View File

@@ -15,7 +15,7 @@ from django.template import RequestContext
from django.utils.hashcompat import sha_constructor, md5_constructor from django.utils.hashcompat import sha_constructor, md5_constructor
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from base.models import FileContributors, UserStarredFiles, DirFilesLastModifiedInfo from base.models import FileContributors, UserStarredFiles, DirFilesLastModifiedInfo, FileLastModifiedInfo
from htmldiff import HtmlDiff from htmldiff import HtmlDiff
@@ -406,6 +406,54 @@ def check_and_get_org_by_group(group_id, user):
return org, base_template return org, base_template
def calc_file_last_modified(repo_id, file_path, file_path_hash, file_id):
try:
# get the lastest one file revision
commits = seafserv_threaded_rpc.list_file_revisions(repo_id, file_path, 1, -1)
except SearpcError, e:
return '', 0
if not commits:
return '', 0
email, last_modified = commits[0].creator_name, commits[0].ctime
info = FileLastModifiedInfo(repo_id=repo_id,
file_path=file_path,
file_path_hash=file_path_hash,
file_id=file_id,
last_modified=last_modified,
email=email)
try:
info.save()
except IntegrityError:
pass
return email, last_modified
def get_file_last_modified(repo_id, file_path):
email = ''
last_modified = 0
file_path_hash = calc_file_path_hash(file_path)
file_id = seafserv_threaded_rpc.get_file_id_by_path(repo_id, file_path)
try:
fc = FileLastModifiedInfo.objects.get(repo_id=repo_id,
file_path_hash=file_path_hash)
except FileLastModifiedInfo.DoesNotExist:
# has no cache yet
user, last_modified = calc_file_last_modified(repo_id, file_path, file_path_hash, file_id)
else:
# cache found
if fc.file_id != file_id:
# but cache is outdated
fc.delete()
user, last_modified = calc_file_last_modified(repo_id, file_path, file_path_hash, file_id)
else:
# cache is valid
user, last_modified = fc.email, fc.last_modified
return user, last_modified
def get_file_contributors_from_revisions(repo_id, file_path): def get_file_contributors_from_revisions(repo_id, file_path):
"""Inspect the file history and get a list of users who have modified the """Inspect the file history and get a list of users who have modified the
it. it.
@@ -413,7 +461,7 @@ def get_file_contributors_from_revisions(repo_id, file_path):
""" """
commits = [] commits = []
try: try:
commits = seafserv_threaded_rpc.list_file_revisions(repo_id, file_path, -1) commits = seafserv_threaded_rpc.list_file_revisions(repo_id, file_path, -1, -1)
except SearpcError, e: except SearpcError, e:
return [], 0, '' return [], 0, ''
@@ -770,48 +818,58 @@ def is_textual_file(file_type):
else: else:
return False return False
if getattr(settings, 'ENABLE_FILE_SEARCH', False):
from seafes import es_get_conn, es_search
from seafes import es_get_conn, es_search conn = es_get_conn()
def search_file_by_name(request, keyword, start, size):
owned_repos, shared_repos, groups_repos, pub_repo_list = get_user_repos(request.user)
conn = es_get_conn() # unify the repo.owner property
for repo in owned_repos:
repo.owner = request.user.username
for repo in shared_repos:
repo.owner = repo.user
for repo in pub_repo_list:
repo.owner = repo.user
def search_file_by_name(request, keyword, start, size): pubrepo_id_map = {}
owned_repos, shared_repos, groups_repos, pub_repo_list = get_user_repos(request.user) for repo in pub_repo_list:
# fix pub repo obj attr name mismatch in seafile/lib/repo.vala
repo.id = repo.repo_id
repo.name = repo.repo_name
pubrepo_id_map[repo.id] = repo
# unify the repo.owner property # get a list of pure non-pub repos
for repo in owned_repos: nonpub_repo_list = []
repo.owner = request.user.username for repo in owned_repos + shared_repos + groups_repos:
for repo in shared_repos: if repo.id not in pubrepo_id_map:
repo.owner = repo.user nonpub_repo_list.append(repo)
for repo in pub_repo_list:
repo.owner = repo.user
pubrepo_id_map = {} nonpub_repo_ids = [ repo.id for repo in nonpub_repo_list]
for repo in pub_repo_list:
# fix pub repo obj attr name mismatch in seafile/lib/repo.vala
repo.id = repo.repo_id
repo.name = repo.repo_name
pubrepo_id_map[repo.id] = repo
# get a list of pure non-pub repos files_found, total = es_search(conn, nonpub_repo_ids, keyword, start, size)
nonpub_repo_list = []
for repo in owned_repos + shared_repos + groups_repos:
if repo.id not in pubrepo_id_map:
nonpub_repo_list.append(repo)
nonpub_repo_ids = [ repo.id for repo in nonpub_repo_list] if len(files_found) > 0:
# construt a (id, repo) hash table for fast lookup
repo_id_map = {}
for repo in nonpub_repo_list:
repo_id_map[repo.id] = repo
files_found, total = es_search(conn, nonpub_repo_ids, keyword, start, size) repo_id_map.update(pubrepo_id_map)
if len(files_found) > 0: for f in files_found:
# construt a (id, repo) hash table for fast lookup repo = repo_id_map.get(f['repo_id'].encode('UTF-8'), None)
repo_id_map = {} if repo:
for repo in nonpub_repo_list: f['repo'] = repo
repo_id_map[repo.id] = repo f['exists'] = True
f['last_modified_by'], f['last_modified'] = get_file_last_modified(f['repo_id'], f['fullpath'])
else:
f['exists'] = False
repo_id_map.update(pubrepo_id_map) files_found = filter(lambda f: f['exists'], files_found)
for f in files_found: return files_found, total
f['repo'] = repo_id_map[f['repo_id'].encode('UTF-8')] else:
def search_file_by_name(*args):
return files_found, total pass