mirror of
https://github.com/correl/codereview.git
synced 2025-04-13 01:01:01 -09:00
Merge branch 'feature/search' into develop
This commit is contained in:
commit
f7aa1b5bf2
17 changed files with 283 additions and 0 deletions
dashboard
media
review
search_sites.pysettings.pytemplates
urls.py
0
dashboard/management/__init__.py
Normal file
0
dashboard/management/__init__.py
Normal file
0
dashboard/management/commands/__init__.py
Normal file
0
dashboard/management/commands/__init__.py
Normal file
24
dashboard/management/commands/updaterepos.py
Normal file
24
dashboard/management/commands/updaterepos.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
import sys
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from codereview.dashboard.models import Repository
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = '<repositoryname repositoryname ...>'
|
||||
help = 'Updates commit information in the database required for searching'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
repos = []
|
||||
if len(args):
|
||||
# Loop through the arguments to get the repos to update
|
||||
for arg in args:
|
||||
try:
|
||||
repo = Repository.objects.get(name=arg)
|
||||
if repo not in repos:
|
||||
repos.append(repo)
|
||||
except:
|
||||
print >> sys.stderr, "Unknown repository '%s'" % arg
|
||||
else:
|
||||
repos = Repository.objects.all()
|
||||
for repo in repos:
|
||||
print 'Updating repo', repo
|
||||
repo.update()
|
|
@ -1,4 +1,6 @@
|
|||
from collections import deque
|
||||
from django.db import models
|
||||
from codereview.browser import vcs
|
||||
|
||||
class Repository(models.Model):
|
||||
name = models.CharField(max_length=200, unique=True)
|
||||
|
@ -10,5 +12,76 @@ class Repository(models.Model):
|
|||
("browse", "Browse repositories"),
|
||||
)
|
||||
|
||||
def update(self):
|
||||
repo = vcs.create(self.type, self.path)
|
||||
branches = repo.branches()
|
||||
for branch, commit in branches.iteritems():
|
||||
print 'Updating', branch
|
||||
try:
|
||||
head = Head.objects.get(repository=self, name=branch)
|
||||
except:
|
||||
head = Head(repository=self, name=branch)
|
||||
try:
|
||||
c = Commit.objects.get(repository=self, ref=commit.id)
|
||||
except:
|
||||
c = Commit(repository=self, ref=commit.id)
|
||||
c.load(repo)
|
||||
head.commit = c
|
||||
head.save()
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Commit(models.Model):
|
||||
ref = models.CharField(max_length=40)
|
||||
repository = models.ForeignKey(Repository)
|
||||
message = models.TextField()
|
||||
author = models.CharField(max_length=255)
|
||||
author_email = models.CharField(max_length=255)
|
||||
committer = models.CharField(max_length=255)
|
||||
committer_email = models.CharField(max_length=255)
|
||||
authored_date = models.DateTimeField()
|
||||
committed_date = models.DateTimeField()
|
||||
parents = models.ManyToManyField('self')
|
||||
|
||||
def load(self, repo):
|
||||
queue = deque([self])
|
||||
while queue:
|
||||
c = queue.popleft()
|
||||
commit = repo.commit(c.ref)
|
||||
c.message = commit.message
|
||||
c.author = commit.author
|
||||
c.author_email = commit.author_email
|
||||
c.committer = commit.committer
|
||||
c.committer_email = commit.committer_email
|
||||
c.authored_date = commit.authored_date
|
||||
c.committed_date = commit.committed_date
|
||||
c.save()
|
||||
print 'Loading', c.ref
|
||||
for parent in commit.parents:
|
||||
try:
|
||||
p = Commit.objects.get(ref=parent, repository=c.repository)
|
||||
except:
|
||||
p = Commit(ref=parent, repository=c.repository)
|
||||
parent = repo.commit(parent)
|
||||
p.message = parent.message
|
||||
p.author = parent.author
|
||||
p.author_email = parent.author_email
|
||||
p.committer = parent.committer
|
||||
p.committer_email = parent.committer_email
|
||||
p.authored_date = parent.authored_date
|
||||
p.committed_date = parent.committed_date
|
||||
p.save()
|
||||
queue.append(p)
|
||||
print 'Queuing', p.ref
|
||||
c.parents.add(p)
|
||||
c.save()
|
||||
def __unicode__(self):
|
||||
return self.ref
|
||||
|
||||
class Head(models.Model):
|
||||
repository = models.ForeignKey(Repository)
|
||||
commit = models.ForeignKey(Commit)
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
|
8
dashboard/search_indexes.py
Normal file
8
dashboard/search_indexes.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from haystack.indexes import *
|
||||
from haystack import site
|
||||
from codereview.dashboard.models import Commit
|
||||
|
||||
class CommitIndex(SearchIndex):
|
||||
text = CharField(document=True, use_template=True)
|
||||
|
||||
site.register(Commit, CommitIndex)
|
|
@ -5,6 +5,9 @@ body, th, td {
|
|||
a {
|
||||
color: black;
|
||||
}
|
||||
.searchbar {
|
||||
float: right;
|
||||
}
|
||||
div.navigation {
|
||||
width: 300px;
|
||||
float: left;
|
||||
|
@ -122,3 +125,22 @@ table.diff tr.annotation td {
|
|||
.comment .text {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.searchresult {
|
||||
border: 1px solid black;
|
||||
margin-bottom: 1em;
|
||||
border-radius: .5em;
|
||||
background-color: #ddd;
|
||||
}
|
||||
.searchresult .header,
|
||||
.searchresult .preview,
|
||||
.searchresult .footer {
|
||||
padding: .5em;
|
||||
}
|
||||
.searchresult .header {
|
||||
font-weight: bold;
|
||||
}
|
||||
.searchresult .preview {
|
||||
padding: 1em;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
|
8
review/search_indexes.py
Normal file
8
review/search_indexes.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from haystack.indexes import *
|
||||
from haystack import site
|
||||
from codereview.review.models import Review
|
||||
|
||||
class ReviewIndex(SearchIndex):
|
||||
text = CharField(document=True, use_template=True)
|
||||
|
||||
site.register(Review, ReviewIndex)
|
2
search_sites.py
Normal file
2
search_sites.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
import haystack
|
||||
haystack.autodiscover()
|
|
@ -84,6 +84,9 @@ AUTHENTICATION_BACKENDS = (
|
|||
'codereview.dashboard.auth.PAMBackend',
|
||||
)
|
||||
|
||||
HAYSTACK_SITECONF = 'codereview.search_sites'
|
||||
HAYSTACK_SEARCH_ENGINE = 'simple'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
||||
# Always use forward slashes, even on Windows.
|
||||
|
@ -100,6 +103,8 @@ INSTALLED_APPS = (
|
|||
# Uncomment the next line to enable the admin:
|
||||
'django.contrib.admin',
|
||||
|
||||
'haystack',
|
||||
|
||||
'codereview.dashboard',
|
||||
'codereview.browser',
|
||||
'codereview.review',
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
{{ user }}
|
||||
|
||||
<a href="{% url django.contrib.auth.views.logout %}">Log Out</a>
|
||||
<form class="searchbar" method="get" action="/search/">
|
||||
<label>Search</label>
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="navigation">
|
||||
|
@ -36,6 +41,7 @@
|
|||
{% endblock %}
|
||||
</div>
|
||||
<div class="content">
|
||||
</form>
|
||||
{% block content %}
|
||||
This space intentionally left blank.
|
||||
{% endblock %}
|
||||
|
|
32
templates/search/includes/dashboard/commit.html
Normal file
32
templates/search/includes/dashboard/commit.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
{% extends 'search/includes/layout.html' %}
|
||||
{% load gravatar %}
|
||||
{% load vcs %}
|
||||
|
||||
{% block url %}
|
||||
{% url codereview.browser.views.commit repository=result.object.repository.name ref=result.object.ref %}
|
||||
{% endblock %}
|
||||
|
||||
{% block type %}
|
||||
Commit
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
{{ result.object.ref }} -
|
||||
{{ result.object.message|oneline|truncatewords:10 }}</a>
|
||||
{% endblock %}
|
||||
{% block preview %}
|
||||
<dl>
|
||||
<dt>Author</dt>
|
||||
<dd>
|
||||
<img src="{{ result.object.author_email|gravatar:16 }}" />
|
||||
{{ result.object.author }}
|
||||
</dd>
|
||||
<dt>Committer</dt>
|
||||
<dd>
|
||||
<img src="{{ result.object.committer_email|gravatar:16 }}" />
|
||||
{{ result.object.committer}}
|
||||
</dd>
|
||||
</dl>
|
||||
<hr />
|
||||
<div class="message">{{ result.object.message|linebreaks }}</div>
|
||||
{% endblock %}
|
21
templates/search/includes/layout.html
Normal file
21
templates/search/includes/layout.html
Normal file
|
@ -0,0 +1,21 @@
|
|||
<div class="searchresult">
|
||||
<div class="header">
|
||||
<span class="type">
|
||||
{% block type %}
|
||||
Unknown Object
|
||||
{% endblock %}
|
||||
:
|
||||
</span>
|
||||
<span class="title">
|
||||
{% block title %}
|
||||
{% endblock %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="preview">
|
||||
{% block preview %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<a href="{% block url %}{% endblock %}">View</a>
|
||||
</div>
|
||||
</div>
|
28
templates/search/includes/review/review.html
Normal file
28
templates/search/includes/review/review.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
{% extends 'search/includes/layout.html' %}
|
||||
|
||||
{% block url %}
|
||||
{% url codereview.review.views.edit review_id=result.object.id %}
|
||||
{% endblock %}
|
||||
|
||||
{% block type %}
|
||||
Review
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
#{{ result.object.id }} -
|
||||
{{ result.object.description|truncatewords:10 }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block preview %}
|
||||
<dl>
|
||||
<dt>Commit</dt>
|
||||
<dd>{{ result.object.ref }}</dd>
|
||||
<dt>Parent</dt>
|
||||
<dd>{{ result.object.parent }}</dd>
|
||||
</dl>
|
||||
<hr />
|
||||
<p>
|
||||
{{ result.object.description|linebreaksbr }}
|
||||
</p>
|
||||
{{ result.object.comment_set.count }} Comment(s)
|
||||
{% endblock %}
|
3
templates/search/indexes/dashboard/commit_text.txt
Normal file
3
templates/search/indexes/dashboard/commit_text.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
{{ object.author }}
|
||||
{{ object.committer }}
|
||||
{{ object.message }}
|
12
templates/search/indexes/review/review_text.txt
Normal file
12
templates/search/indexes/review/review_text.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
{{ object.author }}
|
||||
{{ object.description }}
|
||||
{{ object.ref }} {{ object.parent }}
|
||||
|
||||
{% for comment in object.comment_set.all %}
|
||||
{{ comment.author }}
|
||||
{{ comment.text }}
|
||||
{% for response in comment.response_set.all %}
|
||||
{{ response.author }}
|
||||
{{ response.text }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
37
templates/search/search.html
Normal file
37
templates/search/search.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
{% extends 'layouts/default.html' %}
|
||||
{% block content %}
|
||||
<h2>Search</h2>
|
||||
|
||||
<form method="get" action=".">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="submit" value="Search" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
{% if query %}
|
||||
<h3>Results</h3>
|
||||
{% for result in page.object_list %}
|
||||
{% if result.content_type == 'dashboard.commit' %}
|
||||
{% include 'search/includes/dashboard/commit.html' %}
|
||||
{% endif %}
|
||||
{% if result.content_type == 'review.review' %}
|
||||
{% include 'search/includes/review/review.html' %}
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<p>No results found.</p>
|
||||
{% endfor %}
|
||||
|
||||
{% if page.has_previous or page.has_next %}
|
||||
<div>
|
||||
{% if page.has_previous %}<a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}« Previous{% if page.has_previous %}</a>{% endif %}
|
||||
|
|
||||
{% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}Next »{% if page.has_next %}</a>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# Show some example queries to run, maybe query syntax, something else? #}
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock %}
|
2
urls.py
2
urls.py
|
@ -13,6 +13,8 @@ urlpatterns = patterns('',
|
|||
(r'^dashboard/', include('codereview.dashboard.urls')),
|
||||
(r'^review/', include('codereview.review.urls')),
|
||||
|
||||
(r'^search/', include('haystack.urls')),
|
||||
|
||||
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
|
||||
# to INSTALLED_APPS to enable admin documentation:
|
||||
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
|
Loading…
Add table
Reference in a new issue