summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askbot/api.py3
-rw-r--r--askbot/conf/group_settings.py2
-rw-r--r--askbot/context.py16
-rw-r--r--askbot/models/__init__.py10
-rw-r--r--askbot/models/group.py39
-rw-r--r--askbot/models/post.py16
-rw-r--r--askbot/models/question.py20
-rw-r--r--askbot/models/tag.py37
-rw-r--r--askbot/models/widgets.py2
-rw-r--r--askbot/skins/common/media/js/utils.js116
-rw-r--r--askbot/skins/default/media/style/style.css155
-rw-r--r--askbot/skins/default/media/style/style.less28
-rw-r--r--askbot/skins/default/templates/meta/bottom_scripts.html8
-rw-r--r--askbot/skins/default/templates/widgets/meta_nav.html5
-rw-r--r--askbot/tests/db_api_tests.py12
-rw-r--r--askbot/urls.py5
-rw-r--r--askbot/views/commands.py20
-rw-r--r--askbot/views/users.py14
18 files changed, 409 insertions, 99 deletions
diff --git a/askbot/api.py b/askbot/api.py
index 9f37995e..52bdab3e 100644
--- a/askbot/api.py
+++ b/askbot/api.py
@@ -5,8 +5,9 @@ api must become a place to manupulate the data in the askbot application
so that other implementations of the data storage could be possible
"""
from django.db.models import Q
-from askbot import models
+
from askbot import const
+from askbot import models
def get_info_on_moderation_items(user):
"""returns a dictionary with
diff --git a/askbot/conf/group_settings.py b/askbot/conf/group_settings.py
index 2933b831..75323136 100644
--- a/askbot/conf/group_settings.py
+++ b/askbot/conf/group_settings.py
@@ -20,7 +20,7 @@ settings.register(
)
def group_name_update_callback(old_name, new_name):
- from askbot.models.tag import get_global_group, clean_group_name
+ from askbot.models.group import get_global_group, clean_group_name
cleaned_new_name = clean_group_name(new_name.strip())
if new_name == '':
diff --git a/askbot/context.py b/askbot/context.py
index 402183ea..30718972 100644
--- a/askbot/context.py
+++ b/askbot/context.py
@@ -4,6 +4,9 @@ and the application available for the templates
"""
import sys
from django.conf import settings
+from django.core.urlresolvers import reverse
+from django.utils import simplejson
+
import askbot
from askbot import api
from askbot import models
@@ -11,6 +14,7 @@ from askbot import const
from askbot.conf import settings as askbot_settings
from askbot.skins.loaders import get_skin
from askbot.utils import url_utils
+from askbot.utils.slug import slugify
def application_settings(request):
"""The context processor function"""
@@ -55,9 +59,17 @@ def application_settings(request):
}
if askbot_settings.GROUPS_ENABLED:
- context['group_list'] = models.Tag.group_tags.get_all().filter(
+ groups = models.Tag.group_tags.get_all().filter(
deleted=False
).exclude(
- name__startswith='_internal_')
+ name__startswith='_internal_').values('id', 'name')
+ group_list = []
+ for group in groups:
+ group_slug = slugify(group['name'])
+ link = reverse('users_by_group',
+ kwargs={'group_id': group['id'],
+ 'group_slug': group_slug})
+ group_list.append({'name': group['name'], 'link': link})
+ context['group_list'] = simplejson.dumps(group_list)
return context
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index 549f3277..adf7fb90 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -38,10 +38,8 @@ from askbot.models.question import QuestionView, AnonymousQuestion
from askbot.models.question import DraftQuestion
from askbot.models.question import FavoriteQuestion
from askbot.models.tag import Tag, MarkedTag
-from askbot.models.tag import get_global_group
-from askbot.models.tag import get_group_names
-from askbot.models.tag import get_groups
from askbot.models.tag import format_personal_group_name
+from askbot.models.group import get_groups, get_global_group
from askbot.models.user import EmailFeedSetting, ActivityAuditStatus, Activity
from askbot.models.user import GroupMembership, GroupProfile
from askbot.models.post import Post, PostRevision
@@ -3352,7 +3350,6 @@ def add_user_to_global_group(sender, instance, created, **kwargs):
``instance`` is an instance of ``User`` class
"""
if created:
- from askbot.models.tag import get_global_group
instance.edit_group_membership(
group=get_global_group(),
user=instance,
@@ -3500,6 +3497,7 @@ signals.post_updated.connect(record_post_update_activity)
signals.post_revision_published.connect(notify_author_of_published_revision)
signals.site_visited.connect(record_user_visit)
+
__all__ = [
'signals',
@@ -3538,6 +3536,6 @@ __all__ = [
'get_model',
'get_admins_and_moderators',
- 'get_group_names',
- 'get_groups'
+ 'get_groups',
+ 'get_global_group',
]
diff --git a/askbot/models/group.py b/askbot/models/group.py
new file mode 100644
index 00000000..768b19bb
--- /dev/null
+++ b/askbot/models/group.py
@@ -0,0 +1,39 @@
+import re
+from askbot.models.tag import Tag
+from askbot.conf import settings as askbot_settings
+
+def get_global_group():
+ """Returns the global group,
+ if necessary, creates one
+ """
+ #todo: when groups are disconnected from tags,
+ #find comment as shown below in the test cases and
+ #revert the values
+ #todo: change groups to django groups
+ group_name = askbot_settings.GLOBAL_GROUP_NAME
+ try:
+ return Tag.group_tags.get(name=group_name)
+ except Tag.DoesNotExist:
+ from askbot.models import get_admin
+ return Tag.group_tags.get_or_create(
+ group_name=group_name,
+ user=get_admin(),
+ is_open=False
+ )
+
+def get_groups():
+ return Tag.group_tags.get_all()
+
+def get_group_names():
+ #todo: cache me
+ return get_groups().values_list('name', flat = True)
+
+def get_group_manager():
+ #This will be the place to replace with the new model
+ return Tag.group_tags
+
+def clean_group_name(name):
+ """group names allow spaces,
+ tag names do not, so we use this method
+ to replace spaces with dashes"""
+ return re.sub('\s+', '-', name.strip())
diff --git a/askbot/models/post.py b/askbot/models/post.py
index 9c24637e..72a64fa7 100644
--- a/askbot/models/post.py
+++ b/askbot/models/post.py
@@ -29,8 +29,8 @@ from askbot.models.user import Activity
from askbot.models.user import EmailFeedSetting
from askbot.models.user import GroupMembership
from askbot.models.tag import Tag, MarkedTag
-from askbot.models.tag import get_groups, tags_match_some_wildcard
-from askbot.models.tag import get_global_group
+from askbot.models.tag import tags_match_some_wildcard
+from askbot.models.group import get_groups, get_global_group
from askbot.conf import settings as askbot_settings
from askbot import exceptions
from askbot.utils import markup
@@ -242,7 +242,7 @@ class PostManager(BaseQuerySetManager):
comment = const.POST_STATUS['default_version'],
by_email = by_email
)
-
+
return post
#todo: instead of this, have Thread.add_answer()
@@ -578,7 +578,7 @@ class Post(models.Model):
for group in groups:
for comment in comments:
PostToGroup.objects.get_or_create(post=comment, tag=group)
-
+
def remove_from_groups(self, groups):
PostToGroup.objects.filter(post=self, tag__in=groups).delete()
@@ -658,7 +658,7 @@ class Post(models.Model):
post=self,
recipients=notify_sets['for_email'],
)
-
+
def make_private(self, user, group_id = None):
"""makes post private within user's groups
todo: this is a copy-paste in thread and post
@@ -1248,7 +1248,7 @@ class Post(models.Model):
result['for_mentions'] = set(mentioned_users) - set(exclude_list)
#what users are included depends on the post type
#for example for question - all Q&A contributors
- #are included, for comments only authors of comments and parent
+ #are included, for comments only authors of comments and parent
#post are included
result['for_inbox'] = self.get_response_receivers(exclude_list=exclude_list)
@@ -1945,7 +1945,7 @@ class PostRevision(models.Model):
text = models.TextField()
approved = models.BooleanField(default=False, db_index=True)
- approved_by = models.ForeignKey(User, null = True, blank = True)
+ approved_by = models.ForeignKey(User, null = True, blank = True)
approved_at = models.DateTimeField(null = True, blank = True)
by_email = models.BooleanField(default = False)#true, if edited by email
@@ -2026,7 +2026,7 @@ class PostRevision(models.Model):
body_text = body_text,
recipient_list = [self.author.email,],
)
-
+
else:
message = _(
'Your post was placed on the moderation queue '
diff --git a/askbot/models/question.py b/askbot/models/question.py
index 17e334f4..a3704107 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -16,13 +16,13 @@ from askbot.conf import settings as askbot_settings
from askbot import mail
from askbot.mail import messages
from askbot.models.tag import Tag
-from askbot.models.tag import get_groups
-from askbot.models.tag import get_global_group
+from askbot.models.group import get_global_group
+from askbot.models.group import get_groups
from askbot.models.tag import get_tags_by_names
from askbot.models.tag import filter_accepted_tags, filter_suggested_tags
from askbot.models.tag import delete_tags, separate_unused_tags
from askbot.models.base import DraftContent, BaseQuerySetManager
-from askbot.models.tag import Tag, get_groups
+from askbot.models.tag import Tag
from askbot.models.post import Post, PostRevision
from askbot.models.post import PostToGroup
from askbot.models import signals
@@ -197,7 +197,7 @@ class ThreadManager(BaseQuerySetManager):
# TODO: add a possibility to see deleted questions
qs = self.filter(
- posts__post_type='question',
+ posts__post_type='question',
posts__deleted=False
) # (***) brings `askbot_post` into the SQL query, see the ordering section below
@@ -235,7 +235,7 @@ class ThreadManager(BaseQuerySetManager):
) # TODO: unify with search_state.author ?
#unified tags - is list of tags taken from the tag selection
- #plus any tags added to the query string with #tag or [tag:something]
+ #plus any tags added to the query string with #tag or [tag:something]
#syntax.
#run tag search in addition to these unified tags
meta_data = {}
@@ -477,7 +477,7 @@ class Thread(models.Model):
score = models.IntegerField(default = 0)
objects = ThreadManager()
-
+
class Meta:
app_label = 'askbot'
@@ -663,7 +663,7 @@ class Thread(models.Model):
return 'thread-data-%s-%s' % (self.id, sort_method)
def invalidate_cached_post_data(self):
- """needs to be called when anything notable
+ """needs to be called when anything notable
changes in the post data - on votes, adding,
deleting, editing content"""
#we can call delete_many() here if using Django > 1.2
@@ -823,8 +823,8 @@ class Thread(models.Model):
url = question_post.get_absolute_url()
title = thread.get_title(question_post)
result.append({'url': url, 'title': title})
-
- return result
+
+ return result
def get_cached_data():
"""similar thread data will expire
@@ -859,7 +859,7 @@ class Thread(models.Model):
return False
def add_child_posts_to_groups(self, groups):
- """adds questions and answers of the thread to
+ """adds questions and answers of the thread to
given groups, comments are taken care of implicitly
by the underlying ``Post`` methods
"""
diff --git a/askbot/models/tag.py b/askbot/models/tag.py
index 7c5d8d97..2c6e5e67 100644
--- a/askbot/models/tag.py
+++ b/askbot/models/tag.py
@@ -8,25 +8,6 @@ from askbot import const
from askbot.conf import settings as askbot_settings
from askbot.utils import category_tree
-def get_global_group():
- """Returns the global group,
- if necessary, creates one
- """
- #todo: when groups are disconnected from tags,
- #find comment as shown below in the test cases and
- #revert the values
- #todo: change groups to django groups
- group_name = askbot_settings.GLOBAL_GROUP_NAME
- try:
- return Tag.group_tags.get(name=group_name)
- except Tag.DoesNotExist:
- from askbot.models import get_admin
- return Tag.group_tags.get_or_create(
- group_name=group_name,
- user=get_admin(),
- is_open=False
- )
-
def delete_tags(tags):
"""deletes tags in the list"""
tag_ids = [tag.id for tag in tags]
@@ -89,7 +70,7 @@ def separate_unused_tags(tags):
return used, unused
def tags_match_some_wildcard(tag_names, wildcard_tags):
- """Same as
+ """Same as
:meth:`~askbot.models.tag.TagQuerySet.tags_match_some_wildcard`
except it works on tag name strings
"""
@@ -291,6 +272,7 @@ class GroupTagQuerySet(TagQuerySet):
def get_for_user(self, user=None, private=False):
if private:
+ from askbot.models.group import get_global_group
global_group = get_global_group()
return self.filter(
user_memberships__user=user
@@ -306,15 +288,10 @@ class GroupTagQuerySet(TagQuerySet):
)
def get_by_name(self, group_name = None):
+ from askbot.models.group import clean_group_name
return self.get(name = clean_group_name(group_name))
-def clean_group_name(name):
- """group names allow spaces,
- tag names do not, so we use this method
- to replace spaces with dashes"""
- return re.sub('\s+', '-', name.strip())
-
class GroupTagManager(BaseQuerySetManager):
"""manager for group tags"""
@@ -326,6 +303,7 @@ class GroupTagManager(BaseQuerySetManager):
#todo: here we might fill out the group profile
#replace spaces with dashes
+ from askbot.models.group import clean_group_name
group_name = clean_group_name(group_name)
try:
#iexact is important!!! b/c we don't want case variants
@@ -390,10 +368,3 @@ class MarkedTag(models.Model):
class Meta:
app_label = 'askbot'
-
-def get_groups():
- return Tag.group_tags.get_all()
-
-def get_group_names():
- #todo: cache me
- return get_groups().values_list('name', flat = True)
diff --git a/askbot/models/widgets.py b/askbot/models/widgets.py
index f062e317..274cc9b1 100644
--- a/askbot/models/widgets.py
+++ b/askbot/models/widgets.py
@@ -3,7 +3,7 @@ from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from askbot.conf import settings as askbot_settings
from askbot.models import Tag
-from askbot.models.tag import get_groups
+from askbot.models.group import get_groups
from askbot.forms import FormWithHideableFields, TagNamesField
from askbot.conf import settings as askbot_settings
from django import forms
diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js
index 9b08d66c..53775ecb 100644
--- a/askbot/skins/common/media/js/utils.js
+++ b/askbot/skins/common/media/js/utils.js
@@ -1557,6 +1557,122 @@ SelectBox.prototype.decorate = function(element){
});
};
+/**
+ * This is a dropdown list elment
+ */
+
+var GroupDropdown = function(groups){
+ WrappedElement.call(this);
+ this._group_list = groups;
+ this._input_box = new TippedInput();
+ this._input_box.setInstruction('group name');
+ this._input_box.createDom();
+ this._input_box_element = this._input_box.getElement();
+ this._input_box_element.attr('class', 'group-name');
+ this._input_box_element.hide();
+ this._add_link = this.makeElement('a');
+ this._add_link.attr('href', '#');
+ this._add_link.attr('class', 'group-name');
+ this._add_link.text('add new group');
+};
+inherits(GroupDropdown, WrappedElement);
+
+GroupDropdown.prototype.createDom = function(){
+ this._element = this.makeElement('ul');
+ this._element.attr('class', 'dropdown-menu');
+ this._element.attr('id', 'groups-dropdown');
+ this._element.attr('role', 'menu');
+ this._element.attr('aria-labelledby', 'navGroups');
+
+ for (i=0; i<this._group_list.length; i++){
+ li_element = this.makeElement('li');
+ a_element = this.makeElement('a');
+ a_element.text(this._group_list[i].name);
+ a_element.attr('href', this._group_list[i].link);
+ a_element.attr('class', 'group-name');
+ li_element.append(a_element);
+ this._element.append(li_element);
+ }
+};
+
+GroupDropdown.prototype.decorate = function(element){
+ this._element = element;
+ this._element.attr('class', 'dropdown-menu');
+ this._element.attr('id', 'groups-dropdown');
+ this._element.attr('role', 'menu');
+ this._element.attr('aria-labelledby', 'navGroups');
+
+ for (i=0; i<this._group_list.length; i++){
+ li_element = this.makeElement('li');
+ a_element = this.makeElement('a');
+ a_element.text(this._group_list[i].name);
+ a_element.attr('href', this._group_list[i].link);
+ a_element.attr('class', 'group-name');
+ li_element.append(a_element);
+ this._element.append(li_element);
+ }
+};
+
+GroupDropdown.prototype.prependGroup = function(group_name, url){
+ new_group_li = this.makeElement('li');
+ new_group_a = this.makeElement('a');
+ new_group_a.attr('href', url);
+ new_group_a.attr('class', 'group-name');
+ new_group_a.text(group_name);
+ new_group_li.append(new_group_a);
+ this._element.prepend(new_group_li);
+};
+
+GroupDropdown.prototype._add_group_handler = function(group_name){
+ var group_name = this._input_box_element.val();
+ self = this;
+ if (!group_name){
+ return;
+ }
+
+ $.ajax({
+ type: 'POST',
+ url: askbot['urls']['add_group'],
+ data: {group: group_name},
+ success: function(data){
+ if (data.success){
+ self.prependGroup(data.group_name, data.url);
+ self._input_box_element.hide();
+ self._add_link.show();
+ return true;
+ } else{
+ return false;
+ }
+ },
+ error: function(){console.log('error');}
+ });
+};
+
+GroupDropdown.prototype.enableAddGroups = function(){
+ var self = this;
+ this._add_link.click(function(){
+ self._add_link.hide();
+ self._input_box_element.show();
+ self._input_box_element.focus();
+ });
+ this._input_box_element.keydown(function(event){
+ if (event.which == 13 || event.keyCode==13){
+ self._add_group_handler();
+ self._input_box_element.val('');
+ }
+ });
+
+ var divider = this.makeElement('li');
+ divider.attr('class', 'divider');
+ this._element.append(divider);
+
+ var container = this.makeElement('li');
+ container.append(this._add_link);
+ container.append(this._input_box_element);
+
+ this._element.append(container);
+};
+
var Tag = function(){
SimpleControl.call(this);
this._deletable = false;
diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css
index 55f5806f..ca9ed050 100644
--- a/askbot/skins/default/media/style/style.css
+++ b/askbot/skins/default/media/style/style.css
@@ -68,7 +68,8 @@ select {
margin-left: 0px;
}
input[type="text"].prompt,
-input[type="password"].prompt {
+input[type="password"].prompt,
+input.tipped-input.blank {
font-style: italic;
color: #707070;
}
@@ -313,14 +314,36 @@ body.user-messages {
#metaNav #navTags {
background: 0px -95px url(../images/sprites.png) no-repeat;
}
-#metaNav #navUsers {
- background: 3px -132px url(../images/sprites.png) no-repeat;
-}
+#metaNav #navUsers,
#metaNav #navGroups {
- background: 3px -132px url(../images/sprites.png) no-repeat;
+ background: 3px -133px url(../images/sprites.png) no-repeat;
+}
+#metaNav #navBadges {
+ background: 3px -170px url(../images/sprites.png) no-repeat;
}
#metaNav a.group-name {
padding: 0px;
+ float: center;
+ margin: 5px 0px 5px 10px;
+}
+#metaNav input.group-name {
+ border-top: none;
+ border-left: none;
+ border-right: none;
+ border-bottom: #e2e2ae 1px solid;
+ color: #e2e2ae;
+ height: 25px;
+ font-size: 18px;
+ font-weight: 100;
+ text-decoration: none;
+ display: block;
+ float: left;
+}
+#metaNav input.group-name:focus {
+ border: none;
+}
+#metaNav a.group-name:hover {
+ background-color: transparent;
}
#metaNav span.dropdown:hover ul.dropdown-menu {
display: block;
@@ -329,8 +352,6 @@ body.user-messages {
float: left;
}
#metaNav .dropdown-menu {
- /*top: 120%;*/
-
left: 7%;
}
#header.with-logo #userToolsNav {
@@ -1432,7 +1453,7 @@ ul#related-tags li {
color: #1b79bd;
border-top: #f0f0ec 1px solid;
border-left: #f0f0ec 1px solid;
- height: 30px;
+ min-height: 30px;
line-height: 30px;
font-weight: normal;
}
@@ -1491,6 +1512,7 @@ ul#related-tags li {
.edit-question-page table.proxy-user-info,
.edit-answer-page table.proxy-user-info {
border-spacing: 0px;
+ width: 100%;
}
.ask-page table.proxy-user-info .form-item,
.question-page table.proxy-user-info .form-item,
@@ -1577,6 +1599,80 @@ ul#related-tags li {
width: 395px;
font-size: 14px;
}
+.groups-input,
+.users-input {
+ width: 152px;
+ padding-left: 5px;
+ border: #c9c9b5 1px solid;
+ height: 25px;
+ font-size: 14px;
+}
+.add-groups,
+.add-users {
+ border: 0;
+ font-weight: bold;
+ margin-top: -2px;
+ height: 27px;
+ font-size: 14px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+}
+.add-everyone-group {
+ text-align: center;
+ margin: auto;
+ display: block;
+ padding: 0 10px;
+}
+.add-groups:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+#id_user,
+#id_user_author {
+ border: #cce6ec 3px solid;
+ height: 25px;
+ padding-left: 5px;
+ width: 395px;
+ font-size: 14px;
+}
.title-desc {
color: #707070;
font-size: 13px;
@@ -2302,6 +2398,7 @@ ul#related-tags li {
}
.question-page .answer .vote-buttons {
float: left;
+ margin-top: 10px;
}
.question-page .accepted-answer {
background-color: #f7fecc;
@@ -3133,9 +3230,6 @@ table.form-as-table th {
table.ab-subscr-form {
width: 45em;
}
-table.ab-tag-filter-form {
- width: 45em;
-}
.submit-row {
line-height: 30px;
padding-top: 10px;
@@ -3146,10 +3240,16 @@ table.ab-tag-filter-form {
line-height: 20px;
color: red;
}
-.error {
+.error,
+.openid-signin p.error {
color: darkred;
margin: 0;
- font-size: 10px;
+ font-size: 12px;
+ font-weight: bold;
+ text-align: left;
+}
+.openid-signin p.error {
+ text-align: center;
}
label.retag-error {
color: darkred;
@@ -3549,6 +3649,9 @@ p.signup_p {
list-style-position: outside;
margin: 0;
}
+.simple-subscribe-options input {
+ display: inline;
+}
/* a workaround to set link colors correctly */
.wmd-preview a {
color: #1b79bd;
@@ -3764,6 +3867,11 @@ body.anon.lang-es #searchBar .searchInputCancelable {
color: white;
background: #b32f2f;
}
+.question-page .post-update-info a.primary-group-name,
+a.primary-group-name {
+ color: #990E08;
+ font-weight: bold;
+}
.users-page .wmd-prompt-dialog {
background: #ccc;
}
@@ -3795,6 +3903,17 @@ img.group-logo {
#groups-list td {
padding-bottom: 5px;
}
+.groups-page #groups-list th,
+.groups-page #groups-list td {
+ padding-right: 20px;
+}
+.groups-page #groups-list th {
+ font-weight: bold;
+}
+.groups-page #groups-list th:nth-child(2),
+.groups-page #groups-list td:nth-child(2) {
+ text-align: center;
+}
#reject-edit-modal input,
#reject-edit-modal textarea {
width: 514px;
@@ -3897,12 +4016,18 @@ textarea.tipped-input {
margin-top: 8px;
height: 13px;
}
-.tag-editor input.new-tags-input {
- border-style: none;
+.tag-editor input.new-tags-input,
+.tag-editor input.new-tags-input:focus {
+ border: none;
font-size: 15px;
font-color: #707070;
line-height: 16px;
margin-top: 9px;
+ -webkit-box-shadow: none;
+ /* undo bootstrap glow */
+
+ -moz-box-shadow: none;
+ box-shadow: none;
}
/* fixes for bootstrap */
.caret {
diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less
index 8b443c73..a381c29a 100644
--- a/askbot/skins/default/media/style/style.less
+++ b/askbot/skins/default/media/style/style.less
@@ -313,7 +313,7 @@ body.user-messages {
}
#navTags{
- .sprites(0px,-95px)
+ .sprites(0px,-95px);
}
#navUsers,
@@ -327,6 +327,31 @@ body.user-messages {
a.group-name {
padding: 0px;
+ float:center;
+ margin:5px 0px 5px 10px;
+ }
+
+ input.group-name{
+ border-top:none;
+ border-left:none;
+ border-right:none;
+ border-bottom: #e2e2ae 1px solid;
+ color: #e2e2ae;
+ height: 25px;
+ font-size: 18px;
+ font-weight: 100;
+ text-decoration: none;
+ display: block;
+ float: left;
+
+ }
+
+ input.group-name:focus{
+ border:none;
+ }
+
+ a.group-name:hover{
+ background-color: transparent;
}
span.dropdown:hover ul.dropdown-menu {
@@ -338,7 +363,6 @@ body.user-messages {
}
.dropdown-menu{
- /*top: 120%;*/
left: 7%;
}
diff --git a/askbot/skins/default/templates/meta/bottom_scripts.html b/askbot/skins/default/templates/meta/bottom_scripts.html
index ea763b76..de829bb7 100644
--- a/askbot/skins/default/templates/meta/bottom_scripts.html
+++ b/askbot/skins/default/templates/meta/bottom_scripts.html
@@ -75,6 +75,14 @@
if (askbot['data']['userIsAdminOrMod']) {
$('body').addClass('admin');
}
+ {%if settings.GROUPS_ENABLED %}
+ askbot['urls']['add_group'] = "{% url add_group %}";
+ var group_dropdown = new GroupDropdown({{group_list}});
+ $('.dropdown').append(group_dropdown.getElement());
+ {%if request.user.is_superuser%}
+ group_dropdown.enableAddGroups();
+ {%endif%}
+ {% endif %}
});
{% if user_messages %}
$('#validate_email_alert').click(function(){notify.close(true)})
diff --git a/askbot/skins/default/templates/widgets/meta_nav.html b/askbot/skins/default/templates/widgets/meta_nav.html
index 659780c4..20c22491 100644
--- a/askbot/skins/default/templates/widgets/meta_nav.html
+++ b/askbot/skins/default/templates/widgets/meta_nav.html
@@ -11,11 +11,6 @@
href="{% url groups %}" data-target="#" >
{% trans %}people & groups{% endtrans %}
</a>
-<ul id="groups-dropdown" class="dropdown-menu" role="menu" aria-labelledby="navGroups">
- {%for group in group_list%}
- <li>{{ macros.user_group_link(group) }}</li>
- {%endfor%}
-</ul>
</span>
{%else%}
<a
diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py
index 07590487..32c4ebb3 100644
--- a/askbot/tests/db_api_tests.py
+++ b/askbot/tests/db_api_tests.py
@@ -1,4 +1,4 @@
-"""Tests database api - the basic data entry
+"""Tests database api - the basic data entry
functions that happen on behalf of users
e.g. ``some_user.do_something(...)``
@@ -13,7 +13,7 @@ from askbot.tests.utils import AskbotTestCase
from askbot import models
from askbot import const
from askbot.conf import settings as askbot_settings
-from askbot.models.tag import get_global_group
+from askbot.models.group import get_global_group
import datetime
class DBApiTests(AskbotTestCase):
@@ -249,7 +249,7 @@ class UserLikeTagTests(AskbotTestCase):
self.setup_wildcard('aouaou* o* on* oeu*', 'bad')
self.assert_affinity_is('like', False)
self.assert_affinity_is('dislike', True)
-
+
self.setup_wildcard('one*', 'good')
self.assert_affinity_is('like', True)
self.assert_affinity_is('dislike', False)
@@ -297,7 +297,7 @@ class GlobalTagSubscriberGetterTests(AskbotTestCase):
self.assertEquals(actual_subscribers, expected_subscribers)
def test_nobody_likes_any_tags(self):
- """no-one had marked tags, so the set
+ """no-one had marked tags, so the set
of subscribers must be empty
"""
self.assert_subscribers_are(
@@ -430,7 +430,7 @@ class TagAndGroupTests(AskbotTestCase):
'question_comment': question_comment,
'answer_comment': answer_comment
}
-
+
def test_group_cannot_create_case_variant_tag(self):
self.post_question(user = self.u1, tags = 'one two three')
models.Tag.group_tags.get_or_create(user = self.u1, group_name = 'One')
@@ -546,7 +546,7 @@ class TagAndGroupTests(AskbotTestCase):
self.assertObjectGroupsEqual(data['question_comment'], groups)
self.assertObjectGroupsEqual(data['answer'], groups)
self.assertObjectGroupsEqual(data['answer_comment'], groups)
-
+
data['thread'].make_public(recursive=True)
global_group = get_global_group()
diff --git a/askbot/urls.py b/askbot/urls.py
index 62ae8b54..e553f947 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -273,6 +273,11 @@ urlpatterns = patterns('',
name = 'delete_group_logo'
),
url(#ajax only
+ r'^add-group/',
+ views.commands.add_group,
+ name = 'add_group'
+ ),
+ url(#ajax only
r'^toggle-group-profile-property/',
views.commands.toggle_group_profile_property,
name = 'toggle_group_profile_property'
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 50a94d6a..14990b52 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -20,11 +20,12 @@ from django.utils import simplejson
from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.utils.translation import string_concat
+from askbot.utils.slug import slugify
from askbot import models
from askbot import forms
from askbot.conf import should_show_sort_by_relevance
from askbot.conf import settings as askbot_settings
-from askbot.models.tag import get_global_group
+from askbot.models.group import get_global_group
from askbot.utils import category_tree
from askbot.utils import decorators
from askbot.utils import url_utils
@@ -932,6 +933,23 @@ def save_group_logo_url(request):
else:
raise ValueError('invalid data found when saving group logo')
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+@decorators.admins_only
+def add_group(request):
+ group_name = request.POST.get('group')
+ if group_name:
+ group = models.Tag.group_tags.get_or_create(
+ group_name=group_name,
+ user=request.user,
+ )
+
+ url = reverse('users_by_group', kwargs={'group_id': group.id,
+ 'group_slug': slugify(group_name)})
+ response_dict = dict(group_name = group_name,
+ url = url )
+ return response_dict
@csrf.csrf_exempt
@decorators.ajax_only
diff --git a/askbot/views/users.py b/askbot/views/users.py
index c5b95390..ddb60f13 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -37,8 +37,8 @@ from askbot.conf import settings as askbot_settings
from askbot import models
from askbot import exceptions
from askbot.models.badges import award_badges_signal
-from askbot.models.tag import get_global_group
-from askbot.models.tag import get_groups
+from askbot.models.group import get_global_group, get_groups
+from askbot.models.group import get_group_manager
from askbot.skins.loaders import render_into_skin
from askbot.search.state_manager import SearchState
from askbot.utils import url_utils
@@ -81,7 +81,7 @@ def show_users(request, by_group=False, group_id=None, group_slug=None):
return HttpResponseRedirect('groups')
else:
try:
- group = models.Tag.group_tags.get(id = group_id)
+ group = get_group_manager().get(id = group_id)
group_email_moderation_enabled = \
(
askbot_settings.GROUP_EMAIL_ADDRESSES_ENABLED \
@@ -462,7 +462,7 @@ def user_stats(request, user, context):
badges = badges_dict.items()
badges.sort(key=operator.itemgetter(1), reverse=True)
- user_groups = models.Tag.group_tags.get_for_user(user = user)
+ user_groups = get_group_manager().get_for_user(user = user)
user_groups = user_groups.exclude(name__startswith='_internal_')
global_group = get_global_group()
user_groups = user_groups.exclude(name=global_group.name)
@@ -1011,11 +1011,9 @@ def groups(request, id = None, slug = None):
scope = 'all-groups'
if scope == 'all-groups':
- groups = models.Tag.group_tags.get_all()
+ groups = get_groups()
else:
- groups = models.Tag.group_tags.get_for_user(
- user = request.user
- )
+ groups = get_group_manager().get_for_user(user=request.user)
groups = groups.exclude(name__startswith='_internal_')
groups = groups.annotate(users_count=Count('user_memberships'))