summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-03-30 01:29:28 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2012-03-30 01:29:28 -0400
commit16be92eaae3e04162bc5b44bdb4be848cb12587c (patch)
treeeff05bcb698e8d9df5a22a3f43d71ae7692b7545
parent07fd67e215437a7343ded7c9a6b3212a9965b262 (diff)
downloadaskbot-16be92eaae3e04162bc5b44bdb4be848cb12587c.tar.gz
askbot-16be92eaae3e04162bc5b44bdb4be848cb12587c.tar.bz2
askbot-16be92eaae3e04162bc5b44bdb4be848cb12587c.zip
group logo can be saved and displayed
-rw-r--r--askbot/forms.py5
-rw-r--r--askbot/migrations/0116_auto__add_field_groupprofile_logo_url__add_unique_emailfeedsetting_sub.py304
-rw-r--r--askbot/models/tag.py3
-rw-r--r--askbot/models/user.py6
-rw-r--r--askbot/skins/common/media/js/post.js113
-rw-r--r--askbot/skins/default/templates/users.html61
-rw-r--r--askbot/urls.py5
-rw-r--r--askbot/utils/file_utils.py3
-rw-r--r--askbot/views/commands.py23
-rw-r--r--askbot/views/writers.py10
10 files changed, 491 insertions, 42 deletions
diff --git a/askbot/forms.py b/askbot/forms.py
index ca0d18bd..f71a5520 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -1140,6 +1140,11 @@ class SimpleEmailSubscribeForm(forms.Form):
email_settings_form = EFF(initial=EFF.NO_EMAIL_INITIAL)
email_settings_form.save(user, save_unbound=True)
+class GroupLogoURLForm(forms.Form):
+ """form for saving group logo url"""
+ group_id = forms.IntegerField()
+ image_url = forms.CharField()
+
class EditGroupMembershipForm(forms.Form):
"""a form for adding or removing users
to and from user groups"""
diff --git a/askbot/migrations/0116_auto__add_field_groupprofile_logo_url__add_unique_emailfeedsetting_sub.py b/askbot/migrations/0116_auto__add_field_groupprofile_logo_url__add_unique_emailfeedsetting_sub.py
new file mode 100644
index 00000000..12f123b3
--- /dev/null
+++ b/askbot/migrations/0116_auto__add_field_groupprofile_logo_url__add_unique_emailfeedsetting_sub.py
@@ -0,0 +1,304 @@
+# -*- 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 field 'GroupProfile.logo_url'
+ db.add_column('askbot_groupprofile', 'logo_url',
+ self.gf('django.db.models.fields.URLField')(max_length=200, null=True),
+ keep_default=False)
+
+ # Adding unique constraint on 'EmailFeedSetting', fields ['subscriber', 'feed_type']
+ db.create_unique('askbot_emailfeedsetting', ['subscriber_id', 'feed_type'])
+
+ def backwards(self, orm):
+ # Removing unique constraint on 'EmailFeedSetting', fields ['subscriber', 'feed_type']
+ db.delete_unique('askbot_emailfeedsetting', ['subscriber_id', 'feed_type'])
+
+ # Deleting field 'GroupProfile.logo_url'
+ db.delete_column('askbot_groupprofile', 'logo_url')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'revision_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'to': "orm['askbot.Post']"}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': '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'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ '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'}),
+ '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'})
+ }
+ }
+
+ complete_apps = ['askbot'] \ No newline at end of file
diff --git a/askbot/models/tag.py b/askbot/models/tag.py
index 6e92bab9..06171067 100644
--- a/askbot/models/tag.py
+++ b/askbot/models/tag.py
@@ -109,6 +109,9 @@ class GroupTagManager(TagManager):
except self.model.DoesNotExist:
tag = self.model(name = group_name, created_by = user)
tag.save()
+ from askbot.models.user import GroupProfile
+ group_profile = GroupProfile(group_tag = tag)
+ group_profile.save()
return tag
#todo: maybe move this to query set
diff --git a/askbot/models/user.py b/askbot/models/user.py
index f0d1994e..4127bb64 100644
--- a/askbot/models/user.py
+++ b/askbot/models/user.py
@@ -292,6 +292,8 @@ class EmailFeedSetting(models.Model):
class Meta:
#added to make account merges work properly
unique_together = ('subscriber', 'feed_type')
+ app_label = 'askbot'
+
def __str__(self):
if self.reported_at is None:
@@ -332,9 +334,6 @@ class EmailFeedSetting(models.Model):
self.reported_at = datetime.datetime.now()
self.save()
- class Meta:
- app_label = 'askbot'
-
class GroupMembership(models.Model):
"""an explicit model to link users and the tags
@@ -354,6 +353,7 @@ class GroupProfile(models.Model):
unique = True,
related_name = 'group_profile'
)
+ logo_url = models.URLField(null = True)
class Meta:
app_label = 'askbot'
diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js
index 17e95455..bf5d539a 100644
--- a/askbot/skins/common/media/js/post.js
+++ b/askbot/skins/common/media/js/post.js
@@ -1965,31 +1965,6 @@ WMD.prototype.getMarkdown = function(){
};
WMD.prototype.start = function(){
- Attacklab.loadEnv = function()
- {
- var mergeEnv = function(env)
- {
- if(!env)
- {
- return;
- }
-
- for(var key in env)
- {
- Attacklab.wmd_env[key] = env[key];
- }
- };
-
- mergeEnv(Attacklab.wmd_defaults);
- mergeEnv(Attacklab.account_options);
- mergeEnv(top["wmd_options"]);
- Attacklab.full = true;
-
- var defaultButtons = "bold italic link blockquote code image ol ul heading hr";
- Attacklab.wmd_env.buttons = Attacklab.wmd_env.buttons || defaultButtons;
- };
- Attacklab.loadEnv();
- Attacklab.wmdBase();
Attacklab.Util.startEditor();
setupButtonEventHandlers(this._save_btn, this._save_handler);
this._textarea.keyup(makeKeyHandler(27, this._escape_handler));
@@ -2082,6 +2057,94 @@ TagWikiEditor.prototype.decorate = function(element){
setupButtonEventHandlers(edit_link, function(){ me.startActivatingEditor() });
};
+var ImageChanger = function(){
+ WrappedElement.call(this);
+ this._image_element = undefined;
+};
+inherits(ImageChanger, WrappedElement);
+
+ImageChanger.prototype.setImageElement = function(image_element){
+ this._image_element = image_element;
+};
+
+ImageChanger.prototype.setSaveUrl = function(url){
+ this._save_url = url;
+};
+
+ImageChanger.prototype.setAjaxData = function(data){
+ this._ajax_data = data;
+};
+
+ImageChanger.prototype.showImage = function(image_url){
+ this._image_element.attr('src', image_url);
+};
+
+ImageChanger.prototype.saveImageUrl = function(image_url){
+ var me = this;
+ var data = this._ajax_data;
+ data['image_url'] = image_url;
+ var save_url = this._save_url;
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: save_url,
+ data: data,
+ cache: false,
+ success: function(data){
+ if (!data['success']){
+ showMessage(me.getElement(), data['message'], 'after');
+ }
+ }
+ });
+};
+
+ImageChanger.prototype.startDialog = function(){
+ //reusing the wmd's file uploader
+ var me = this;
+ Attacklab.Util.prompt(
+ "<p style='margin-top: 0px'>" + gettext('enter the logo url') + '</p>',
+ 'http://',
+ function(image_url){
+ me.saveImageUrl(image_url);
+ me.showImage(image_url);
+ },
+ 'image'
+ );
+};
+
+/**
+ * decorates an element that will serve as the image changer button
+ */
+ImageChanger.prototype.decorate = function(element){
+ this._element = element;
+ var me = this;
+ setupButtonEventHandlers(
+ element,
+ function(){
+ me.startDialog();
+ }
+ );
+};
+
+var UserGroupProfileEditor = function(){
+ TagWikiEditor.call(this);
+};
+inherits(UserGroupProfileEditor, TagWikiEditor);
+
+UserGroupProfileEditor.prototype.decorate = function(element){
+ UserGroupProfileEditor.superClass_.decorate.call(this, element);
+ var change_logo_btn = element.find('.change_logo');
+ this._change_logo_btn = change_logo_btn;
+
+ var logo_changer = new ImageChanger();
+ logo_changer.setImageElement(element.find('.group-logo'));
+ logo_changer.setAjaxData({
+ group_id: this.getTagId()
+ });
+ logo_changer.setSaveUrl(askbot['urls']['save_group_logo_url']);
+ logo_changer.decorate(change_logo_btn);
+};
+
$(document).ready(function() {
$('[id^="comments-for-"]').each(function(index, element){
var comments = new PostCommentsWidget();
diff --git a/askbot/skins/default/templates/users.html b/askbot/skins/default/templates/users.html
index 6ad2d77c..557c1a77 100644
--- a/askbot/skins/default/templates/users.html
+++ b/askbot/skins/default/templates/users.html
@@ -50,18 +50,28 @@
<span>{% trans %}Nothing found.{% endtrans %}</span>
{% endif %}
</p>
-<div id="group-wiki-{{group.id}}">
- <div class="content">
- {% if group.tag_wiki %}
- {{ group.tag_wiki.html }}
+{% if group %}
+ <div id="group-wiki-{{group.id}}">
+ <img class="group-logo"
+ {% if group.group_profile.logo_url %}
+ src="{{ group.group_profile.logo_url }}"
+ {% endif %}
+ />
+ <div class="content">
+ {% if group.tag_wiki %}
+ {{ group.tag_wiki.html }}
+ {% endif %}
+ </div>
+ {% if request.user.is_authenticated() and request.user.is_administrator_or_moderator() %}
+ <a class="edit">
+ {% trans %}edit group description{% endtrans %}
+ </a>
+ <a class="change_logo">
+ {% trans %}add/change logo{% endtrans %}
+ </a>
{% endif %}
</div>
- {% if request.user.is_authenticated() and request.user.is_administrator_or_moderator() %}
- <a class="edit">
- {% trans %}edit group description{% endtrans %}
- </a>
- {% endif %}
-</div>
+{% endif %}
{{ macros.user_list(
users.object_list,
karma_mode = settings.KARMA_MODE, badges_mode = settings.BADGES_MODE
@@ -75,9 +85,12 @@
<script type='text/javascript'>
var Attacklab = Attacklab || {};
Attacklab.wmd = 1;{# a trick to launch wmd manually #}
+ askbot['urls']['upload'] = '{% url upload %}';
askbot['urls']['load_tag_wiki_text'] = '{% url load_tag_wiki_text %}';
askbot['urls']['save_tag_wiki_text'] = '{% url save_tag_wiki_text %}';
+ askbot['urls']['save_group_logo_url'] = '{% url save_group_logo_url %}';
</script>
+ <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
@@ -86,7 +99,33 @@
//todo move javascript out
$().ready(function(){
if (askbot['data']['userIsAdminOrMod'] === true){
- var group_editor = new TagWikiEditor();
+ //todo: this is kind of Attacklab.init ... should not be here
+ Attacklab.loadEnv = function()
+ {
+ var mergeEnv = function(env)
+ {
+ if(!env)
+ {
+ return;
+ }
+
+ for(var key in env)
+ {
+ Attacklab.wmd_env[key] = env[key];
+ }
+ };
+
+ mergeEnv(Attacklab.wmd_defaults);
+ mergeEnv(Attacklab.account_options);
+ mergeEnv(top["wmd_options"]);
+ Attacklab.full = true;
+
+ var defaultButtons = "bold italic link blockquote code image ol ul heading hr";
+ Attacklab.wmd_env.buttons = Attacklab.wmd_env.buttons || defaultButtons;
+ };
+ Attacklab.loadEnv();
+ Attacklab.wmdBase();
+ var group_editor = new UserGroupProfileEditor();
group_editor.decorate($('#group-wiki-{{group.id}}'));
}
Hilite.exact = false;
diff --git a/askbot/urls.py b/askbot/urls.py
index 9a68e646..9d444e8d 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -202,6 +202,11 @@ urlpatterns = patterns('',
views.commands.save_tag_wiki_text,
name = 'save_tag_wiki_text'
),
+ url(#ajax only
+ r'^save-group-logo-url/',
+ views.commands.save_group_logo_url,
+ name = 'save_group_logo_url'
+ ),
url(
r'^get-groups-list/',
views.commands.get_groups_list,
diff --git a/askbot/utils/file_utils.py b/askbot/utils/file_utils.py
index daca1522..3793b5ce 100644
--- a/askbot/utils/file_utils.py
+++ b/askbot/utils/file_utils.py
@@ -5,7 +5,7 @@ import time
import urlparse
from django.core.files.storage import get_storage_class
-def store_file(file_object):
+def store_file(file_object, file_name_prefix = ''):
"""Creates an instance of django's file storage
object based on the file-like object,
returns the storage object, file name, file url
@@ -16,6 +16,7 @@ def store_file(file_object):
'.',
str(random.randint(0,100000))
) + os.path.splitext(file_object.name)[1].lower()
+ file_name = file_name_prefix + file_name
file_storage = get_storage_class()()
# use default storage to store file
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 8416d486..277d4b95 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -685,6 +685,29 @@ def read_message(request):#marks message a read
@csrf.csrf_exempt
@decorators.ajax_only
@decorators.post_only
+def save_group_logo_url(request):
+ if request.user.is_anonymous():
+ raise exceptions.PermissionDenied()
+
+ if not request.user.is_administrator_or_moderator():
+ raise exceptions.PermissionDenied(
+ _('Only moderators and administrators can change user groups')
+ )
+
+ form = forms.GroupLogoURLForm(request.POST)
+ if form.is_valid():
+ group_id = form.cleaned_data['group_id']
+ image_url = form.cleaned_data['image_url']
+ group = models.Tag.group_tags.get(id = group_id)
+ group.group_profile.logo_url = image_url
+ group.group_profile.save()
+ else:
+ raise ValueError('invalid data found when saving group logo')
+
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
def edit_group_membership(request):
if request.user.is_anonymous():
raise exceptions.PermissionDenied()
diff --git a/askbot/views/writers.py b/askbot/views/writers.py
index d9a6f855..de130ac2 100644
--- a/askbot/views/writers.py
+++ b/askbot/views/writers.py
@@ -62,9 +62,13 @@ def upload(request):#ajax upload file to a question or answer
request.user.assert_can_upload_file()
+ #todo: build proper form validation
+ file_name_prefix = request.POST.get('file_name_prefix', '')
+ if file_name_prefix not in ('', 'group_logo_'):
+ raise exceptions.PermissionDenied('invalid upload file name prefix')
+
# check file type
f = request.FILES['file-upload']
-
#todo: extension checking should be replaced with mimetype checking
#and this must be part of the form validation
file_extension = os.path.splitext(f.name)[1].lower()
@@ -75,7 +79,9 @@ def upload(request):#ajax upload file to a question or answer
raise exceptions.PermissionDenied(msg)
# generate new file name and storage object
- file_storage, new_file_name, file_url = store_file(f)
+ file_storage, new_file_name, file_url = store_file(
+ f, file_name_prefix
+ )
# check file size
# byte
size = file_storage.size(new_file_name)