mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-03 07:55:36 +00:00
add file search
This commit is contained in:
@@ -1915,6 +1915,7 @@ textarea:-moz-placeholder {/* for FF */
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* wiki page */
|
||||
#wiki-area.article {
|
||||
padding: 0 0;
|
||||
@@ -1925,3 +1926,55 @@ textarea:-moz-placeholder {/* for FF */
|
||||
.wiki-page-missing {
|
||||
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" />
|
||||
</a>
|
||||
{% 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>
|
||||
|
||||
@@ -197,6 +203,7 @@ $(document).click(function(e) {
|
||||
$('#account-context').attr('data', 'no-popup');
|
||||
}
|
||||
});
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</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.file import view_file, view_history_file, view_trash_file,\
|
||||
view_snapshot_file
|
||||
from seahub.search import search
|
||||
from notifications.views import notification_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/orgadmin/$', sys_org_admin, name='sys_org_admin'),
|
||||
url(r'^sys/groupadmin/$', sys_group_admin, name='sys_group_admin'),
|
||||
|
||||
url(r'^search/$', search, name='search'),
|
||||
)
|
||||
|
||||
if settings.SERVE_STATIC:
|
||||
@@ -125,4 +128,3 @@ else:
|
||||
url(r'^pubinfo/groups/$', pubgrp, name='pubgrp'),
|
||||
url(r'^pubinfo/users/$', pubuser, name='pubuser'),
|
||||
)
|
||||
|
||||
|
@@ -771,3 +771,47 @@ def is_textual_file(file_type):
|
||||
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