mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-02 23:48:47 +00:00
add file search
This commit is contained in:
@@ -1915,6 +1915,7 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* wiki page */
|
/* wiki page */
|
||||||
#wiki-area.article {
|
#wiki-area.article {
|
||||||
padding: 0 0;
|
padding: 0 0;
|
||||||
@@ -1925,3 +1926,55 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
.wiki-page-missing {
|
.wiki-page-missing {
|
||||||
color:red;
|
color:red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#search-form {
|
||||||
|
float: right;
|
||||||
|
margin-top: 5px;
|
||||||
|
width: 200px;
|
||||||
|
height: 24px;
|
||||||
|
border: 2px solid #CDCDCD;
|
||||||
|
border-color: #9A9A9A #CDCDCD #CDCDCD #9A9A9A;
|
||||||
|
border-radius: 3px;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
-ms-border-radius: 3px;
|
||||||
|
-o-border-radius: 3px;
|
||||||
|
box-shadow: 0 0 0 #000,inset 0px 3px 3px #eee;
|
||||||
|
-moz-box-shadow: 0 0 0 #000,inset 0px 3px 3px #eee;
|
||||||
|
-webkit-box-shadow: 0 0 0 #000,inset 0px 3px 3px #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search-keyword {
|
||||||
|
margin: 0;
|
||||||
|
width: 180px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 2px;
|
||||||
|
padding-left: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 12px;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
background: url('../img/search.png') no-repeat scroll left center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-info {
|
||||||
|
font-size: 16px;
|
||||||
|
border-bottom: 1px solid #8A948F;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-count {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #999;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-info-keyword {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-results {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIN
media/img/search.png
Normal file
BIN
media/img/search.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 402 B |
58
search.py
Normal file
58
search.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import settings
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import simplejson as json
|
||||||
|
import re
|
||||||
|
import tempfile
|
||||||
|
import sys
|
||||||
|
import urllib
|
||||||
|
import urllib2
|
||||||
|
import logging
|
||||||
|
import chardet
|
||||||
|
from urllib import quote
|
||||||
|
from django.core.cache import cache
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.sites.models import Site, RequestSite
|
||||||
|
from django.db import IntegrityError
|
||||||
|
from django.db.models import F
|
||||||
|
from django.http import HttpResponse, HttpResponseBadRequest, Http404, \
|
||||||
|
HttpResponseRedirect
|
||||||
|
from django.shortcuts import render_to_response, redirect
|
||||||
|
from django.template import Context, loader, RequestContext
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
from django.utils.hashcompat import md5_constructor
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.views.generic.base import TemplateView, TemplateResponseMixin
|
||||||
|
from django.views.generic.edit import BaseFormView, FormMixin
|
||||||
|
|
||||||
|
from auth.decorators import login_required
|
||||||
|
|
||||||
|
from seahub.utils import search_file_by_name
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def search(request):
|
||||||
|
keyword = request.GET['keyword']
|
||||||
|
current_page = int(request.GET.get('page', '1'))
|
||||||
|
per_page= int(request.GET.get('per_page', '25'))
|
||||||
|
|
||||||
|
start = (current_page - 1) * per_page
|
||||||
|
size = per_page
|
||||||
|
results, total = search_file_by_name(request, keyword, start, size)
|
||||||
|
|
||||||
|
if total > current_page * per_page:
|
||||||
|
has_more = True
|
||||||
|
else:
|
||||||
|
has_more = False
|
||||||
|
|
||||||
|
return render_to_response('search_results.html', {
|
||||||
|
'keyword': keyword,
|
||||||
|
'results': results,
|
||||||
|
'total': total,
|
||||||
|
'has_more': has_more,
|
||||||
|
'current_page': current_page,
|
||||||
|
'prev_page': current_page - 1,
|
||||||
|
'next_page': current_page + 1,
|
||||||
|
'per_page': per_page,
|
||||||
|
}, context_instance=RequestContext(request))
|
@@ -86,6 +86,12 @@
|
|||||||
<img src="{{ MEDIA_URL }}img/logo.png?t=1362454620" title="Seafile" alt="Seafile logo" />
|
<img src="{{ MEDIA_URL }}img/logo.png?t=1362454620" title="Seafile" alt="Seafile logo" />
|
||||||
</a>
|
</a>
|
||||||
{% block nav %}{% endblock %}
|
{% block nav %}{% endblock %}
|
||||||
|
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
|
<form id="search-form" method="GET" action="{% url 'search' %}">
|
||||||
|
<input id="search-keyword" name="keyword" placeholder="{% trans 'Search Seafile' %}" />
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -162,16 +168,16 @@ $('#info-bar .close').click(function() {
|
|||||||
info_id_exist = false,
|
info_id_exist = false,
|
||||||
new_info_id = $(this).attr('data') + '_';
|
new_info_id = $(this).attr('data') + '_';
|
||||||
date.setTime(date.getTime() + 14*24*60*60*1000);
|
date.setTime(date.getTime() + 14*24*60*60*1000);
|
||||||
new_info_id += '; expires=' + date.toGMTString() + '; path=' + '{{ SITE_ROOT }}';
|
new_info_id += '; expires=' + date.toGMTString() + '; path=' + '{{ SITE_ROOT }}';
|
||||||
for (var i = 0, len = cookies.length; i < len; i++) {
|
for (var i = 0, len = cookies.length; i < len; i++) {
|
||||||
if (cookies[i].split('=')[0] == 'info_id') {
|
if (cookies[i].split('=')[0] == 'info_id') {
|
||||||
info_id_exist = true;
|
info_id_exist = true;
|
||||||
document.cookie = 'info_id=' + cookies[i].split('=')[1] + new_info_id;
|
document.cookie = 'info_id=' + cookies[i].split('=')[1] + new_info_id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!info_id_exist) {
|
if (!info_id_exist) {
|
||||||
document.cookie = 'info_id=' + new_info_id;
|
document.cookie = 'info_id=' + new_info_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -197,6 +203,7 @@ $(document).click(function(e) {
|
|||||||
$('#account-context').attr('data', 'no-popup');
|
$('#account-context').attr('data', 'no-popup');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</script>
|
</script>
|
||||||
|
71
templates/search_results.html
Normal file
71
templates/search_results.html
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{% extends base_template %}
|
||||||
|
|
||||||
|
{% load seahub_tags avatar_tags i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% block right_panel %}
|
||||||
|
<p class="search-info">
|
||||||
|
{% trans 'Search results for' %} <span class="search-info-keyword">"{{ keyword }}"</span>
|
||||||
|
</p>
|
||||||
|
{% if not results %}
|
||||||
|
<p class="search-results-empty">
|
||||||
|
{% trans 'No search result found' %}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="search-result-count">{% trans 'Found' %} {{ total }} {% trans 'results' %} </p>
|
||||||
|
<table class="search-results">
|
||||||
|
<tr>
|
||||||
|
<th width="10%"></th> <!-- icon -->
|
||||||
|
<th width="40%">{% trans 'Name' %}</th>
|
||||||
|
<th width="30%">{% trans 'Library' %}</th>
|
||||||
|
<th width="20%">{% trans 'Owner' %}</th>
|
||||||
|
</tr>
|
||||||
|
{% for file in results %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="{{ MEDIA_URL }}img/file/{{ file.name|file_icon_filter }}" alt="{% trans "File"%}" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'repo_view_file' repo_id=file.repo.id %}?p={{ file.fullpath|urlencode }}">{{ file.name }}</a>
|
||||||
|
({{ file.score }})
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'repo' repo_id=file.repo.id %}">{{ file.repo.name }}</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% avatar file.repo.owner 20 %}
|
||||||
|
<a class="name" href="{% url 'profile.views.user_profile' file.repo.owner %}">{{ file.repo.owner|email2nickname }}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
<div id="paginator">
|
||||||
|
{% if current_page != 1 %}
|
||||||
|
<a href="?keyword={{ keyword|urlencode }}&page={{ prev_page }}&per_page={{ per_page }}">{% trans "Previous"%}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if has_more %}
|
||||||
|
<a href="?keyword={{ keyword|urlencode }}&page={{ next_page }}&per_page={{ per_page }}">{% trans "Next"%}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if current_page != 1 or has_more %}
|
||||||
|
|
|
||||||
|
{% endif %}
|
||||||
|
<span>{% trans "Per page: "%}</span>
|
||||||
|
{% if per_page == 25 %}
|
||||||
|
<span> 25 </span>
|
||||||
|
{% else %}
|
||||||
|
<a href="?keyword={{ keyword|urlencode }}&page={{ current_page }}&per_page=25" class="per-page">25</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if per_page == 50 %}
|
||||||
|
<span> 50 </span>
|
||||||
|
{% else %}
|
||||||
|
<a href="?keyword={{ keyword|urlencode }}&page={{ current_page }}&per_page=50" class="per-page">50</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if per_page == 100 %}
|
||||||
|
<span> 100 </span>
|
||||||
|
{% else %}
|
||||||
|
<a href="?keyword={{ keyword|urlencode }}&page={{ current_page }}&per_page=100" class="per-page">100</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
4
urls.py
4
urls.py
@@ -5,6 +5,7 @@ from django.views.generic.simple import direct_to_template
|
|||||||
from seahub.views import *
|
from seahub.views import *
|
||||||
from seahub.views.file import view_file, view_history_file, view_trash_file,\
|
from seahub.views.file import view_file, view_history_file, view_trash_file,\
|
||||||
view_snapshot_file
|
view_snapshot_file
|
||||||
|
from seahub.search import search
|
||||||
from notifications.views import notification_list
|
from notifications.views import notification_list
|
||||||
from group.views import group_list
|
from group.views import group_list
|
||||||
|
|
||||||
@@ -101,6 +102,8 @@ urlpatterns = patterns('',
|
|||||||
url(r'^sys/useradmin/$', sys_useradmin, name='sys_useradmin'),
|
url(r'^sys/useradmin/$', sys_useradmin, name='sys_useradmin'),
|
||||||
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:
|
||||||
@@ -125,4 +128,3 @@ 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'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -770,4 +770,48 @@ def is_textual_file(file_type):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
pubrepo_id_map = {}
|
||||||
|
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
|
||||||
|
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]
|
||||||
|
|
||||||
|
files_found, total = es_search(conn, nonpub_repo_ids, keyword, start, size)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
repo_id_map.update(pubrepo_id_map)
|
||||||
|
|
||||||
|
for f in files_found:
|
||||||
|
f['repo'] = repo_id_map[f['repo_id'].encode('UTF-8')]
|
||||||
|
|
||||||
|
return files_found, total
|
||||||
|
Reference in New Issue
Block a user