Skip to content

Commit

Permalink
merged in latest Mikes changes
Browse files Browse the repository at this point in the history
  • Loading branch information
evgenyfadeev committed Jul 27, 2009
1 parent 96be321 commit 464c14f
Show file tree
Hide file tree
Showing 26 changed files with 3,946 additions and 185 deletions.
33 changes: 33 additions & 0 deletions INSTALL
@@ -0,0 +1,33 @@
PRE-REQUIREMENTS:
-----------------------------------------------
1. Python2.5, MySQL, Django v1.0+

2. Python-openid v2.2
http://openidenabled.com/python-openid/

3. django-authopenid(Included in project already)
http://code.google.com/p/django-authopenid/

4. html5lib
http://code.google.com/p/html5lib/
Used for HTML sanitizer

5. Markdown2
http://code.google.com/p/python-markdown2/


INSTALL STEPS:
-----------------------------------------------
1. Copy settings_local.py.dist to settings_local.py and
update all your settings. Check settings.py and update
it as well if necessory.

2. Prepare your database by using the same database/account
configuration from above.

3. Run "python manager.py runserver" to startup django
development environment.

4. There are some demo scripts under sql_scripts folder,
including badges and test accounts for CNProg.com. You
don't need them to run your sample.
20 changes: 11 additions & 9 deletions LICENSE
@@ -1,12 +1,14 @@
��Ȩ����(c) 2008 CNProg.com
Copyright (C) 2009. Chen Gang

����2.0�汾Apache����֤("����֤")��Ȩ��
���ݱ�����֤���û����Բ�ʹ�ô��ļ���
�û��ɴ�������ַ�������֤������
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

http://www.apache.org/licenses/LICENSE-2.0
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

���������÷�����Ҫ������ͬ�⣬
��������֤�ַ��������ǻ���"��ԭ��"�����ṩ��
���κ���ʾ�Ļ�ʾ�ı�֤��������
�����������֤�����£��ض����ԵĹ�ϽȨ�޺����ơ�
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
9 changes: 9 additions & 0 deletions context.py
@@ -0,0 +1,9 @@
from django.conf import settings
def application_settings(context):
return {
'APP_TITLE' : settings.APP_TITLE,
'APP_URL' : settings.APP_URL,
'APP_KEYWORDS' : settings.APP_KEYWORDS,
'APP_DESCRIPTION' : settings.APP_DESCRIPTION,
'APP_INTRO' : settings.APP_INTRO
}
30 changes: 30 additions & 0 deletions development.log
@@ -0,0 +1,30 @@
# development

==July 26 2009, Evgeny==

django_authopenid:
considerably changed user interface

log/forum/forms.py:
- added tag input validation using regex
- fixed bug with date type mismatch near self.fields['birthday'] =
in EditUserForm.__init__()

/forum/templatetags/extra_tags.py:
- fixed date type mismatch in get_age()

/templates/content/js/com.cnprog.post.js:
- fixed bug with post deletion/recovery

javascript:
- changed to use of non-minified code - better for editing
and debugging

/templates/question.html:
- fixed display of delete/undelete links

templates:
added comments in the beginning/end of each template
for the debugging purposes - so that you know which template outputs what html
<!-- user_favorites.html -->
<!-- end user_favorites.html -->
4 changes: 2 additions & 2 deletions django_authopenid/models.py
Expand Up @@ -3,7 +3,7 @@
from django.contrib.auth.models import User
from django.db import models

import md5, random, sys, os, time
import hashlib, random, sys, os, time

__all__ = ['Nonce', 'Association', 'UserAssociation',
'UserPasswordQueueManager', 'UserPasswordQueue']
Expand Down Expand Up @@ -47,7 +47,7 @@ def get_new_confirm_key(self):
# The random module is seeded when this Apache child is created.
# Use SECRET_KEY as added salt.
while 1:
confirm_key = md5.new("%s%s%s%s" % (
confirm_key = hashlib.md5("%s%s%s%s" % (
random.randint(0, sys.maxint - 1), os.getpid(),
time.time(), settings.SECRET_KEY)).hexdigest()
try:
Expand Down
4 changes: 2 additions & 2 deletions django_authopenid/util.py
Expand Up @@ -15,7 +15,7 @@
except:
from yadis import xri

import time, base64, md5, operator
import time, base64, hashlib, operator
import urllib

from models import Association, Nonce
Expand Down Expand Up @@ -128,7 +128,7 @@ def cleanupAssociations(self):

def getAuthKey(self):
# Use first AUTH_KEY_LEN characters of md5 hash of SECRET_KEY
return md5.new(settings.SECRET_KEY).hexdigest()[:self.AUTH_KEY_LEN]
return hashlib.md5(settings.SECRET_KEY).hexdigest()[:self.AUTH_KEY_LEN]

def isDumb(self):
return False
Expand Down
37 changes: 30 additions & 7 deletions forum/management/commands/once_award_badges.py
Expand Up @@ -157,7 +157,8 @@ def first_type_award(self):
"""
activity_types = ','.join('%s' % item for item in BADGE_AWARD_TYPE_FIRST.keys())
# ORDER BY user_id, activity_type
query = "SELECT id, user_id, activity_type, content_type_id, object_id FROM activity WHERE is_auditted = 0 AND activity_type IN (%s) ORDER BY user_id, activity_type" % activity_types
query = "SELECT id, user_id, activity_type, content_type_id, object_id "+
"FROM activity WHERE is_auditted = 0 AND activity_type IN (%s) ORDER BY user_id, activity_type" % activity_types

cursor = connection.cursor()
try:
Expand Down Expand Up @@ -205,7 +206,10 @@ def first_ask_be_voted(self):
(13, '学生', 3, '学生', '第一次提问并且有一次以上赞成票', 0, 0),
"""
query = "SELECT act.user_id, q.vote_up_count, act.object_id FROM activity act, question q WHERE act.activity_type = %s AND act.object_id = q.id AND act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ASK_QUESTION, 13)
query = "SELECT act.user_id, q.vote_up_count, act.object_id FROM "+
"activity act, question q WHERE act.activity_type = %s AND "+
"act.object_id = q.id AND "+
"act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ASK_QUESTION, 13)
cursor = connection.cursor()
try:
cursor.execute(query)
Expand All @@ -232,7 +236,10 @@ def first_answer_be_voted(self):
(15, '教师', 3, '教师', '第一次回答问题并且得到一个以上赞成票', 0, 0),
"""
query = "SELECT act.user_id, a.vote_up_count, act.object_id FROM activity act, answer a WHERE act.activity_type = %s AND act.object_id = a.id AND act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 15)
query = "SELECT act.user_id, a.vote_up_count, act.object_id FROM "+
"activity act, answer a WHERE act.activity_type = %s AND "+
"act.object_id = a.id AND "+
"act.user_id NOT IN (SELECT distinct user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 15)
cursor = connection.cursor()
try:
cursor.execute(query)
Expand All @@ -257,7 +264,11 @@ def first_answer_be_voted_10(self):
"""
(32, '学问家', 2, '学问家', '第一次回答被投赞成票10次以上', 0, 0)
"""
query = "SELECT act.user_id, act.object_id FROM activity act, answer a WHERE act.object_id = a.id AND act.activity_type = %s AND a.vote_up_count >= 10 AND act.user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 32)
query = "SELECT act.user_id, act.object_id FROM "+
"activity act, answer a WHERE act.object_id = a.id AND "+
"act.activity_type = %s AND "+
"a.vote_up_count >= 10 AND "+
"act.user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s)" % (TYPE_ACTIVITY_ANSWER, 32)
cursor = connection.cursor()
try:
cursor.execute(query)
Expand All @@ -281,23 +292,35 @@ def vote_count_300(self):
"""
(26, '优秀市民', 2, '优秀市民', '投票300次以上', 0, 0)
"""
query = "SELECT count(*) vote_count, user_id FROM activity WHERE activity_type = %s OR activity_type = %s AND user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) GROUP BY user_id HAVING vote_count >= 300" % (TYPE_ACTIVITY_VOTE_UP, TYPE_ACTIVITY_VOTE_DOWN, 26)
query = "SELECT count(*) vote_count, user_id FROM activity WHERE "+
"activity_type = %s OR "+
"activity_type = %s AND "+
"user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "+
"GROUP BY user_id HAVING vote_count >= 300" % (TYPE_ACTIVITY_VOTE_UP, TYPE_ACTIVITY_VOTE_DOWN, 26)

self.__award_for_count_num(query, 26)

def edit_count_100(self):
"""
(27, '编辑主任', 2, '编辑主任', '编辑了100个帖子', 0, 0)
"""
query = "SELECT count(*) vote_count, user_id FROM activity WHERE activity_type = %s OR activity_type = %s AND user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) GROUP BY user_id HAVING vote_count >= 100" % (TYPE_ACTIVITY_UPDATE_QUESTION, TYPE_ACTIVITY_UPDATE_ANSWER, 27)
query = "SELECT count(*) vote_count, user_id FROM activity WHERE "+
"activity_type = %s OR "+
"activity_type = %s AND "+
"user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "+
"GROUP BY user_id HAVING vote_count >= 100" % (TYPE_ACTIVITY_UPDATE_QUESTION, TYPE_ACTIVITY_UPDATE_ANSWER, 27)

self.__award_for_count_num(query, 27)

def comment_count_10(self):
"""
(5, '评论家', 3, '评论家', '评论10次以上', 0, 0),
"""
query = "SELECT count(*) vote_count, user_id FROM activity WHERE activity_type = %s OR activity_type = %s AND user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) GROUP BY user_id HAVING vote_count >= 10" % (TYPE_ACTIVITY_COMMENT_QUESTION, TYPE_ACTIVITY_COMMENT_ANSWER, 5)
query = "SELECT count(*) vote_count, user_id FROM activity WHERE "+
"activity_type = %s OR "+
"activity_type = %s AND "+
"user_id NOT IN (SELECT user_id FROM award WHERE badge_id = %s) "+
"GROUP BY user_id HAVING vote_count >= 10" % (TYPE_ACTIVITY_COMMENT_QUESTION, TYPE_ACTIVITY_COMMENT_ANSWER, 5)
self.__award_for_count_num(query, 5)

def __award_for_count_num(self, query, badge):
Expand Down
55 changes: 53 additions & 2 deletions forum/managers.py
Expand Up @@ -4,8 +4,29 @@
from django.db import connection, models, transaction
from django.db.models import Q
from forum.models import *
from urllib import quote, unquote

class QuestionManager(models.Manager):
def get_translation_questions(self, orderby, page_size):
questions = self.filter(deleted=False, author__id__in=[28,29]).order_by(orderby)[:page_size]
return questions

def get_questions_by_pagesize(self, orderby, page_size):
questions = self.filter(deleted=False).order_by(orderby)[:page_size]
return questions

def get_questions_by_tag(self, tagname, orderby):
questions = self.filter(deleted=False, tags__name = unquote(tagname)).order_by(orderby)
return questions

def get_unanswered_questions(self, orderby):
questions = self.filter(deleted=False, answer_count=0).order_by(orderby)
return questions

def get_questions(self, orderby):
questions = self.filter(deleted=False).order_by(orderby)
return questions

def update_tags(self, question, tagnames, user):
"""
Updates Tag associations for a question to match the given
Expand Down Expand Up @@ -92,7 +113,12 @@ class TagManager(models.Manager):
'WHERE tag_id = tag.id'
') '
'WHERE id IN (%s)')


def get_valid_tags(self, page_size):
from forum.models import Tag
tags = Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-id")[:page_size]
return tags

def get_or_create_multiple(self, names, user):
"""
Fetches a list of Tags with the given names, creating any Tags
Expand Down Expand Up @@ -123,6 +149,19 @@ def update_use_counts(self, tags):
query = self.UPDATE_USED_COUNTS_QUERY % ','.join(['%s'] * len(tags))
cursor.execute(query, [tag.id for tag in tags])
transaction.commit_unless_managed()

def get_tags_by_questions(self, questions):
question_ids = []
for question in questions:
question_ids.append(question.id)

question_ids_str = ','.join([str(id) for id in question_ids])
related_tags = self.extra(
tables=['tag', 'question_tags'],
where=["tag.id = question_tags.tag_id AND question_tags.question_id IN (" + question_ids_str + ")"]
).distinct()

return related_tags

class AnswerManager(models.Manager):
GET_ANSWERS_FROM_USER_QUESTIONS = u'SELECT answer.* FROM answer INNER JOIN question ON answer.question_id = question.id WHERE question.author_id =%s AND answer.author_id <> %s'
Expand Down Expand Up @@ -205,4 +244,16 @@ def get_reputation_by_upvoted_today(self, user):
return row[0]

else:
return 0
return 0
class AwardManager(models.Manager):
def get_recent_awards(self):
awards = super(AwardManager, self).extra(
select={'badge_id': 'badge.id', 'badge_name':'badge.name',
'badge_description': 'badge.description', 'badge_type': 'badge.type',
'user_id': 'auth_user.id', 'user_name': 'auth_user.username'
},
tables=['award', 'badge', 'auth_user'],
order_by=['-awarded_at'],
where=['auth_user.id=award.user_id AND badge_id=badge.id'],
).values('badge_id', 'badge_name', 'badge_description', 'badge_type', 'user_id', 'user_name')
return awards
3 changes: 2 additions & 1 deletion forum/models.py
Expand Up @@ -351,7 +351,8 @@ class Award(models.Model):
content_object = generic.GenericForeignKey('content_type', 'object_id')
awarded_at = models.DateTimeField(default=datetime.datetime.now)
notified = models.BooleanField(default=False)

objects = AwardManager()

def __unicode__(self):
return u'[%s] is awarded a badge [%s] at %s' % (self.user.username, self.badge.name, self.awarded_at)

Expand Down
20 changes: 10 additions & 10 deletions forum/templatetags/extra_tags.py
@@ -1,4 +1,4 @@
import time
import time
import datetime
import math
import re
Expand Down Expand Up @@ -50,10 +50,10 @@ def tag_font_size(max_size, min_size, current_size):
weight = 0
return MIN_FONTSIZE + round((MAX_FONTSIZE - MIN_FONTSIZE) * weight)


LEADING_PAGE_RANGE_DISPLAYED = TRAILING_PAGE_RANGE_DISPLAYED = 5
LEADING_PAGE_RANGE = TRAILING_PAGE_RANGE = 4
NUM_PAGES_OUTSIDE_RANGE = 1
NUM_PAGES_OUTSIDE_RANGE = 1
ADJACENT_PAGES = 2
@register.inclusion_tag("paginator.html")
def cnprog_paginator(context):
Expand All @@ -65,10 +65,10 @@ def cnprog_paginator(context):
" Initialize variables "
in_leading_range = in_trailing_range = False
pages_outside_leading_range = pages_outside_trailing_range = range(0)

if (context["pages"] <= LEADING_PAGE_RANGE_DISPLAYED):
in_leading_range = in_trailing_range = True
page_numbers = [n for n in range(1, context["pages"] + 1) if n > 0 and n <= context["pages"]]
page_numbers = [n for n in range(1, context["pages"] + 1) if n > 0 and n <= context["pages"]]
elif (context["page"] <= LEADING_PAGE_RANGE):
in_leading_range = True
page_numbers = [n for n in range(1, LEADING_PAGE_RANGE_DISPLAYED + 1) if n > 0 and n <= context["pages"]]
Expand All @@ -77,11 +77,11 @@ def cnprog_paginator(context):
in_trailing_range = True
page_numbers = [n for n in range(context["pages"] - TRAILING_PAGE_RANGE_DISPLAYED + 1, context["pages"] + 1) if n > 0 and n <= context["pages"]]
pages_outside_trailing_range = [n + 1 for n in range(0, NUM_PAGES_OUTSIDE_RANGE)]
else:
else:
page_numbers = [n for n in range(context["page"] - ADJACENT_PAGES, context["page"] + ADJACENT_PAGES + 1) if n > 0 and n <= context["pages"]]
pages_outside_leading_range = [n + context["pages"] for n in range(0, -NUM_PAGES_OUTSIDE_RANGE, -1)]
pages_outside_trailing_range = [n + 1 for n in range(0, NUM_PAGES_OUTSIDE_RANGE)]

extend_url = context.get('extend_url', '')
return {
"base_url": context["base_url"],
Expand Down Expand Up @@ -205,12 +205,12 @@ def format_number(value):
m = re.match(pattern, strValue)
return first + result

@register.simple_tag
@register.simple_tag
def convert2tagname_list(question):
question['tagnames'] = [name for name in question['tagnames'].split(u' ')]
return ''

@register.simple_tag
@register.simple_tag
def diff_date(date, limen=2):
current_time = datetime.datetime(*time.localtime()[0:6])
diff = current_time - date
Expand All @@ -237,4 +237,4 @@ def get_latest_changed_timestamp():
timestr = strftime("%H:%M %b-%d-%Y %Z", localtime(latest))
except:
timestr = ''
return timestr
return timestr
1 change: 1 addition & 0 deletions forum/user.py
@@ -1,3 +1,4 @@
# coding=utf-8
from django.utils.translation import ugettext as _
class UserView:
def __init__(self, id, tab_title, tab_description, page_title, view_name, template_file, data_size=0):
Expand Down

0 comments on commit 464c14f

Please sign in to comment.