mirror of
https://github.com/nikdoof/vapemap.git
synced 2025-12-13 14:32:15 +00:00
Addition of content reporting
New app called "moderation" which handles the reporting, and in the future, management of incorrect records in the database.
This commit is contained in:
0
app/moderation/__init__.py
Normal file
0
app/moderation/__init__.py
Normal file
5
app/moderation/admin.py
Normal file
5
app/moderation/admin.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.contrib import admin
|
||||
from moderation.models import FlagType, FlaggedObject
|
||||
|
||||
admin.site.register(FlagType, admin.ModelAdmin)
|
||||
admin.site.register(FlaggedObject, admin.ModelAdmin)
|
||||
95
app/moderation/migrations/0001_initial.py
Normal file
95
app/moderation/migrations/0001_initial.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'FlagType'
|
||||
db.create_table(u'moderation_flagtype', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
|
||||
('is_active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
))
|
||||
db.send_create_signal(u'moderation', ['FlagType'])
|
||||
|
||||
# Adding model 'FlaggedObject'
|
||||
db.create_table(u'moderation_flaggedobject', (
|
||||
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
|
||||
('object_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
|
||||
('flag_type', self.gf('django.db.models.fields.related.ForeignKey')(related_name='+', to=orm['moderation.FlagType'])),
|
||||
('note', self.gf('django.db.models.fields.TextField')()),
|
||||
('status', self.gf('django.db.models.fields.PositiveIntegerField')(default=1)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, to=orm['auth.User'])),
|
||||
))
|
||||
db.send_create_signal(u'moderation', ['FlaggedObject'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'FlagType'
|
||||
db.delete_table(u'moderation_flagtype')
|
||||
|
||||
# Deleting model 'FlaggedObject'
|
||||
db.delete_table(u'moderation_flaggedobject')
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
u'moderation.flaggedobject': {
|
||||
'Meta': {'object_name': 'FlaggedObject'},
|
||||
'flag_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': u"orm['moderation.FlagType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'object_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
'status': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
u'moderation.flagtype': {
|
||||
'Meta': {'object_name': 'FlagType'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['moderation']
|
||||
0
app/moderation/migrations/__init__.py
Normal file
0
app/moderation/migrations/__init__.py
Normal file
37
app/moderation/models.py
Normal file
37
app/moderation/models.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
try:
|
||||
from django.contrib.auth import get_user_model
|
||||
USER_MODEL = get_user_model()
|
||||
except ImportError:
|
||||
from django.contrib.auth.models import User as USER_MODEL
|
||||
from django.contrib.contenttypes import generic
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
|
||||
DEFAULT_FLAGGING_STATUS = (
|
||||
(1, 'Reported'),
|
||||
(2, 'Updated by Moderator'),
|
||||
(3, 'Deleted by Moderator'),
|
||||
(4, 'No Action'),
|
||||
)
|
||||
FLAGGING_STATUS = getattr(settings, 'FLAGGING_STATUS', DEFAULT_FLAGGING_STATUS)
|
||||
|
||||
|
||||
class FlagType(models.Model):
|
||||
name = models.CharField(max_length=200)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class FlaggedObject(models.Model):
|
||||
object_id = models.PositiveIntegerField()
|
||||
object_type = models.ForeignKey(ContentType)
|
||||
generic_obj = generic.GenericForeignKey('object_type', 'object_id')
|
||||
|
||||
flag_type = models.ForeignKey('moderation.FlagType', related_name='+')
|
||||
note = models.TextField()
|
||||
status = models.PositiveIntegerField(choices=FLAGGING_STATUS, default=1)
|
||||
user = models.ForeignKey(USER_MODEL, related_name='+', null=True, blank=True)
|
||||
1
app/moderation/templates/moderation/flag_button.html
Normal file
1
app/moderation/templates/moderation/flag_button.html
Normal file
@@ -0,0 +1 @@
|
||||
<a class="btn btn-small" href="#report-modal" data-toggle="modal">Report an Issue</a>
|
||||
81
app/moderation/templates/moderation/flag_form.html
Normal file
81
app/moderation/templates/moderation/flag_form.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<div id="report-modal" class="modal hide fade">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h3>Report {{ object }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="type">Type of Issue</label>
|
||||
<div class="controls">
|
||||
<select id="type">
|
||||
{% for type in flagtypes %}
|
||||
<option value="{{ type.pk }}">{{ type.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="note">Note</label>
|
||||
<div class="controls">
|
||||
<textarea id="note" rows=5 class="input-xlarge"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a id="report-button" href="#" class="btn btn-primary" onclick="submit_report()" data-loading-text="Submitting...">Report</a>
|
||||
<script type="text/javascript">
|
||||
function getCookie(name) {
|
||||
var cookieValue = null;
|
||||
if (document.cookie && document.cookie != '') {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = jQuery.trim(cookies[i]);
|
||||
// Does this cookie string begin with the name we want?
|
||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
function bootstrap_alert(message, cls) {
|
||||
$('#alert-container').append('<div class="alert alert-'+cls+'"><a class="close" data-dismiss="alert">×</a>'+message+'</div>')
|
||||
}
|
||||
function submit_report(){
|
||||
$('#report-button').button('loading');
|
||||
var data = {
|
||||
app: '{{ contenttype.app_label }}',
|
||||
model: '{{ contenttype.model }}',
|
||||
id: {{ object.pk }},
|
||||
flag_type: $('select#type').val(),
|
||||
note: $('textarea#note').val()
|
||||
}
|
||||
console.log(data);
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '{% url "moderation_flagobject" %}',
|
||||
data: JSON.stringify(data),
|
||||
dataType: 'json',
|
||||
contentType: "application/json; charset=utf-8",
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}).done(function(data) {
|
||||
bootstrap_alert('Report successfully created for the moderators to review', 'success');
|
||||
$('#report-modal').modal('hide');
|
||||
$('#report-button').button('reset');
|
||||
console.log(data);
|
||||
}).error(function(data){
|
||||
console.log(data);
|
||||
bootstrap_alert('An error was encountered while creating the report. Please try again later.', 'error');
|
||||
$('#report-modal').modal('hide');
|
||||
$('#report-button').button('reset');
|
||||
});
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
1
app/moderation/templatetags/__init__.py
Normal file
1
app/moderation/templatetags/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
18
app/moderation/templatetags/moderation.py
Normal file
18
app/moderation/templatetags/moderation.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from django import template
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from ..models import FlagType
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.inclusion_tag('moderation/flag_form.html')
|
||||
def flag_form(obj):
|
||||
return {
|
||||
'flagtypes': FlagType.objects.filter(is_active=True),
|
||||
'object': obj,
|
||||
'contenttype': ContentType.objects.get_for_model(obj),
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag('moderation/flag_button.html')
|
||||
def flag_button():
|
||||
return {}
|
||||
132
app/moderation/tests.py
Normal file
132
app/moderation/tests.py
Normal file
@@ -0,0 +1,132 @@
|
||||
"""
|
||||
This file demonstrates writing tests using the unittest module. These will pass
|
||||
when you run "manage.py test".
|
||||
|
||||
Replace this with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
import json
|
||||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
try:
|
||||
from django.contrib.auth import get_user_model
|
||||
USER_MODEL = get_user_model()
|
||||
except ImportError:
|
||||
from django.contrib.auth.models import User as USER_MODEL
|
||||
from moderation.models import FlagType, FlaggedObject
|
||||
|
||||
|
||||
class FlagObjectViewTestCase(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.u1 = USER_MODEL.objects.create_user('user1', 'test@test.com', 'user1')
|
||||
self.f1 = FlagType.objects.create(name='Test')
|
||||
|
||||
def tearDown(self):
|
||||
self.u1.delete()
|
||||
self.f1.delete()
|
||||
|
||||
def post_to_flagobject(self, data={}):
|
||||
return self.client.post(reverse('moderation_flagobject'), data, content_type='application/json', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
|
||||
|
||||
def test_invalid_json(self):
|
||||
resp = self.post_to_flagobject('')
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'invalid-request')
|
||||
self.assertEqual(content['reason'], 'invalid-request')
|
||||
|
||||
def test_invalid_json_2(self):
|
||||
resp = self.post_to_flagobject({'data': '1234567890'})
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'invalid-request')
|
||||
self.assertEqual(content['reason'], 'invalid-json')
|
||||
|
||||
def test_missing_app_model_json(self):
|
||||
resp = self.post_to_flagobject(json.dumps({'invalid': 'invalid'}))
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'invalid-request')
|
||||
self.assertEqual(content['reason'], 'no-app-or-model')
|
||||
|
||||
def test_unknown_type(self):
|
||||
resp = self.post_to_flagobject(json.dumps({
|
||||
'app': 'moderation',
|
||||
'model': 'xxxxxxxxxxxxxxxxxxxx',
|
||||
'id': 999999,
|
||||
'flag_type': 1,
|
||||
'note': 'test note',
|
||||
}))
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'invalid-request')
|
||||
self.assertEqual(content['reason'], 'unknown-object-type')
|
||||
|
||||
def test_missing_object(self):
|
||||
resp = self.post_to_flagobject(json.dumps({
|
||||
'app': 'moderation',
|
||||
'model': 'flaggedobject',
|
||||
'id': 999999,
|
||||
'flag_type': 1,
|
||||
'note': 'test note',
|
||||
}))
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'invalid-request')
|
||||
self.assertEqual(content['reason'], 'does-not-exist')
|
||||
|
||||
def test_missing_fields(self):
|
||||
resp = self.post_to_flagobject(json.dumps({
|
||||
'app': 'moderation',
|
||||
'model': 'flaggedobject',
|
||||
'id': 999999,
|
||||
'flag_type': 1,
|
||||
}))
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'invalid-request')
|
||||
self.assertEqual(content['reason'], 'missing-fields')
|
||||
|
||||
def test_flagging_authenticated(self):
|
||||
|
||||
self.client.login(username='user1', password='user1')
|
||||
|
||||
resp = self.post_to_flagobject(json.dumps({
|
||||
'app': 'moderation',
|
||||
'model': 'flagtype',
|
||||
'id': self.f1.pk,
|
||||
'flag_type': 1,
|
||||
'note': 'test note',
|
||||
}))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'ok')
|
||||
self.assertIsNotNone(content['flag_id'])
|
||||
|
||||
flag = FlaggedObject.objects.get(pk=content['flag_id'])
|
||||
self.assertIsNotNone(flag)
|
||||
self.assertEqual(flag.user, self.u1)
|
||||
self.assertEqual(flag.flag_type, self.f1)
|
||||
|
||||
def test_flagging_unauthenticated(self):
|
||||
|
||||
self.client.logout()
|
||||
|
||||
resp = self.post_to_flagobject(json.dumps({
|
||||
'app': 'moderation',
|
||||
'model': 'flagtype',
|
||||
'id': self.f1.pk,
|
||||
'flag_type': 1,
|
||||
'note': 'test note',
|
||||
}))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
content = json.loads(resp.content)
|
||||
self.assertEqual(content['result'], 'ok')
|
||||
self.assertIsNotNone(content['flag_id'])
|
||||
|
||||
flag = FlaggedObject.objects.get(pk=content['flag_id'])
|
||||
self.assertIsNotNone(flag)
|
||||
self.assertEqual(flag.user, None)
|
||||
self.assertEqual(flag.flag_type, self.f1)
|
||||
6
app/moderation/urls.py
Normal file
6
app/moderation/urls.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.conf.urls import patterns, url
|
||||
from moderation.views import FlagObjectView
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^flag/$', FlagObjectView.as_view(), name='moderation_flagobject'),
|
||||
)
|
||||
57
app/moderation/views.py
Normal file
57
app/moderation/views.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import json
|
||||
from django.http import HttpResponseBadRequest
|
||||
from django.views.generic import View
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from braces.views import AjaxResponseMixin, JSONResponseMixin
|
||||
from moderation.models import FlaggedObject
|
||||
|
||||
|
||||
class FlagObjectView(JSONResponseMixin, AjaxResponseMixin, View):
|
||||
"""
|
||||
Ajax capable view to flag a object for moderation
|
||||
"""
|
||||
|
||||
def render_invalid_response(self, reason='invalid-request'):
|
||||
return HttpResponseBadRequest(content=json.dumps({
|
||||
'result': 'invalid-request',
|
||||
'reason': reason,
|
||||
}), content_type=self.get_content_type())
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def post_ajax(self, request, *args, **kwargs):
|
||||
data = request.raw_post_data
|
||||
if not data:
|
||||
return self.render_invalid_response()
|
||||
try:
|
||||
data = json.loads(data)
|
||||
except ValueError:
|
||||
return self.render_invalid_response('invalid-json')
|
||||
if not isinstance(data, dict):
|
||||
return self.render_invalid_response('invalid-json')
|
||||
if not 'app' in data or not 'model' in data:
|
||||
return self.render_invalid_response('no-app-or-model')
|
||||
if not 'flag_type' in data or not 'note' in data:
|
||||
return self.render_invalid_response('missing-fields')
|
||||
try:
|
||||
ct = ContentType.objects.get(app_label=data['app'], model=data['model'])
|
||||
except ContentType.DoesNotExist:
|
||||
return self.render_invalid_response('unknown-object-type')
|
||||
cls = ct.model_class()
|
||||
try:
|
||||
cls.objects.get(pk=data['id'])
|
||||
except cls.DoesNotExist:
|
||||
return self.render_invalid_response('does-not-exist')
|
||||
if request.user.is_authenticated():
|
||||
user = request.user
|
||||
else:
|
||||
user = None
|
||||
flag = FlaggedObject(object_type=ct, object_id=data['id'], flag_type_id=data['flag_type'],
|
||||
note=data['note'], user=user)
|
||||
flag.save()
|
||||
result = {
|
||||
'result': 'ok',
|
||||
'flag_id': flag.pk,
|
||||
}
|
||||
return self.render_json_response(result)
|
||||
164
app/stores/migrations/0006_add_moderation_types.py
Normal file
164
app/stores/migrations/0006_add_moderation_types.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
depends_on = (
|
||||
('moderation', '0001_initial'),
|
||||
)
|
||||
|
||||
def forwards(self, orm):
|
||||
orm['moderation.FlagType'].objects.create(name='Incorrect address')
|
||||
orm['moderation.FlagType'].objects.create(name='Incorrect contact details')
|
||||
orm['moderation.FlagType'].objects.create(name='Does not exist')
|
||||
orm['moderation.FlagType'].objects.create(name='Owner request')
|
||||
orm['moderation.FlagType'].objects.create(name='Wrong store type')
|
||||
|
||||
def backwards(self, orm):
|
||||
pass
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
u'moderation.flaggedobject': {
|
||||
'Meta': {'object_name': 'FlaggedObject'},
|
||||
'flag_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': u"orm['moderation.FlagType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'object_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
'status': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
u'moderation.flagtype': {
|
||||
'Meta': {'object_name': 'FlagType'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
|
||||
},
|
||||
'stores.address': {
|
||||
'Meta': {'object_name': 'Address'},
|
||||
'address1': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'address2': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'address3': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'city': ('django.db.models.fields.CharField', [], {'max_length': "'50'"}),
|
||||
'country': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'addresses'", 'to': "orm['stores.Country']"}),
|
||||
'county': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'addresses'", 'null': 'True', 'to': "orm['stores.County']"}),
|
||||
'geo_latitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'geo_longitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'postcode': ('django.db.models.fields.CharField', [], {'max_length': '20'})
|
||||
},
|
||||
'stores.brand': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Brand'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'stores.chain': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Chain'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'editor': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'editable_chains'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'head_office': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['stores.Address']", 'null': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'long_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'stores.claimrequest': {
|
||||
'Meta': {'object_name': 'ClaimRequest'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'object_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'claims'", 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'stores.country': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Country'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'iso_code': ('django.db.models.fields.CharField', [], {'max_length': '3'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'stores.county': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'County'},
|
||||
'country': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'counties'", 'null': 'True', 'to': "orm['stores.Country']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'stores.link': {
|
||||
'Meta': {'object_name': 'Link'},
|
||||
'account_name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'account_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['stores.LinkType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
|
||||
'object_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"})
|
||||
},
|
||||
'stores.linktype': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'LinkType'},
|
||||
'icon': ('django.db.models.fields.CharField', [], {'default': "'icon-globe'", 'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'url_format': ('django.db.models.fields.CharField', [], {'max_length': '255'})
|
||||
},
|
||||
'stores.store': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'Store'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'address': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'stores'", 'to': "orm['stores.Address']"}),
|
||||
'brands': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['stores.Brand']", 'null': 'True', 'blank': 'True'}),
|
||||
'chain': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'stores'", 'null': 'True', 'to': "orm['stores.Chain']"}),
|
||||
'editor': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'editable_stores'", 'null': 'True', 'to': u"orm['auth.User']"}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'long_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
|
||||
'phone': ('django.db.models.fields.CharField', [], {'max_length': '25', 'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'store_type': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['moderation', 'stores']
|
||||
symmetrical = True
|
||||
@@ -2,6 +2,7 @@
|
||||
{% load markdown_deux_tags %}
|
||||
{% load staticfiles %}
|
||||
{% load waffle_tags %}
|
||||
{% load moderation %}
|
||||
|
||||
{% block title %}
|
||||
{{ chain.name }}
|
||||
@@ -49,6 +50,7 @@
|
||||
{% else %}
|
||||
<p>No description / write up available for this chain at the moment.</p>
|
||||
{% endif %}
|
||||
<p>{% flag_button %}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -74,4 +76,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% flag_form chain %}
|
||||
{% endblock %}
|
||||
@@ -1,13 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
{% load markdown_deux_tags %}
|
||||
{% load waffle_tags %}
|
||||
{% load moderation %}
|
||||
|
||||
{% block title %}
|
||||
{{ store.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
<style type="text/css">
|
||||
<style type="text/css" xmlns="http://www.w3.org/1999/html">
|
||||
.vcard ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
@@ -55,7 +56,9 @@ $(document).ready(function(){initialize_map_store()});
|
||||
{% else %}
|
||||
<p>No description / write up available for this store at the moment.</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p>{% flag_button %}</p>
|
||||
|
||||
{% if store.brands.count %}
|
||||
<h3>Brands Stocked</h3>
|
||||
<ul>
|
||||
@@ -105,5 +108,6 @@ $(document).ready(function(){initialize_map_store()});
|
||||
</noscript>
|
||||
</div>
|
||||
</div>
|
||||
{% flag_form store %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -77,6 +77,7 @@ INSTALLED_APPS = [
|
||||
'bootstrapform',
|
||||
'registration',
|
||||
'haystack',
|
||||
'moderation',
|
||||
'stores',
|
||||
]
|
||||
|
||||
|
||||
@@ -55,7 +55,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="alert-container">
|
||||
{% if messages %}
|
||||
|
||||
{% for message in messages %}
|
||||
<div{% if message.tags %} class="alert alert-{{ message.tags }}"{% endif %}>
|
||||
<a class="close" data-dismiss="alert" href="#">×</a>
|
||||
@@ -63,6 +65,7 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -9,6 +9,7 @@ urlpatterns = patterns('',
|
||||
url(r'user/', include('registration.backends.default.urls')),
|
||||
url(r'user/', include('django.contrib.auth.urls')),
|
||||
url(r'^search/', include('haystack.urls')),
|
||||
url(r'^moderation/', include('moderation.urls')),
|
||||
url('', include('stores.urls'))
|
||||
)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ geopy>=0.95
|
||||
django-markdown-deux>=1.0.4
|
||||
django-bootstrap-form>=1.4
|
||||
django-extra-views>=0.6.2
|
||||
-e git+git://github.com/brack3t/django-braces.git@e0a8f04419eee0ca5809a62cffd3f5d1e80bb059#egg=django_braces
|
||||
-e hg+https://bitbucket.org/alper/django-registration@1cddccb#egg=django_registration
|
||||
requests
|
||||
pyelasticsearch
|
||||
|
||||
Reference in New Issue
Block a user