merge
This commit is contained in:
commit
ca740fef99
10 changed files with 49 additions and 348 deletions
|
@ -5,6 +5,8 @@ local_settings.py
|
|||
.pydevproject
|
||||
.project
|
||||
debug_toolbar
|
||||
django
|
||||
djapian_db
|
||||
*.db
|
||||
*.json
|
||||
*.log
|
||||
|
|
|
@ -1,257 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
r"""
|
||||
phpserialize
|
||||
~~~~~~~~~~~~
|
||||
|
||||
a port of the ``serialize`` and ``unserialize`` functions of
|
||||
php to python. This module implements the python serialization
|
||||
interface (eg: provides `dumps`, `loads` and similar functions).
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
>>> from phpserialize import *
|
||||
>>> obj = dumps("Hello World")
|
||||
>>> loads(obj)
|
||||
'Hello World'
|
||||
|
||||
Due to the fact that PHP doesn't know the concept of lists, lists
|
||||
are serialized like hash-maps in PHP. As a matter of fact the
|
||||
reverse value of a serialized list is a dict:
|
||||
|
||||
>>> loads(dumps(range(2)))
|
||||
{0: 0, 1: 1}
|
||||
|
||||
If you want to have a list again, you can use the `dict_to_list`
|
||||
helper function:
|
||||
|
||||
>>> dict_to_list(loads(dumps(range(2))))
|
||||
[0, 1]
|
||||
|
||||
It's also possible to convert into a tuple by using the `dict_to_tuple`
|
||||
function:
|
||||
|
||||
>>> dict_to_tuple(loads(dumps((1, 2, 3))))
|
||||
(1, 2, 3)
|
||||
|
||||
Another problem are unicode strings. By default unicode strings are
|
||||
encoded to 'utf-8' but not decoded on `unserialize`. The reason for
|
||||
this is that phpserialize can't guess if you have binary or text data
|
||||
in the strings:
|
||||
|
||||
>>> loads(dumps(u'Hello W\xf6rld'))
|
||||
'Hello W\xc3\xb6rld'
|
||||
|
||||
If you know that you have only text data of a known charset in the result
|
||||
you can decode strings by setting `decode_strings` to True when calling
|
||||
loads:
|
||||
|
||||
>>> loads(dumps(u'Hello W\xf6rld'), decode_strings=True)
|
||||
u'Hello W\xf6rld'
|
||||
|
||||
Dictionary keys are limited to strings and integers. `None` is converted
|
||||
into an empty string and floats and booleans into integers for PHP
|
||||
compatibility:
|
||||
|
||||
>>> loads(dumps({None: 14, 42.23: 'foo', True: [1, 2, 3]}))
|
||||
{'': 14, 1: {0: 1, 1: 2, 2: 3}, 42: 'foo'}
|
||||
|
||||
It also provides functions to read from file-like objects:
|
||||
|
||||
>>> from StringIO import StringIO
|
||||
>>> stream = StringIO('a:2:{i:0;i:1;i:1;i:2;}')
|
||||
>>> dict_to_list(load(stream))
|
||||
[1, 2]
|
||||
|
||||
And to write to those:
|
||||
|
||||
>>> stream = StringIO()
|
||||
>>> dump([1, 2], stream)
|
||||
>>> stream.getvalue()
|
||||
'a:2:{i:0;i:1;i:1;i:2;}'
|
||||
|
||||
Like `pickle` chaining of objects is supported:
|
||||
|
||||
>>> stream = StringIO()
|
||||
>>> dump([1, 2], stream)
|
||||
>>> dump("foo", stream)
|
||||
>>> stream.seek(0)
|
||||
>>> load(stream)
|
||||
{0: 1, 1: 2}
|
||||
>>> load(stream)
|
||||
'foo'
|
||||
|
||||
This feature however is not supported in PHP. PHP will only unserialize
|
||||
the first object.
|
||||
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
1.1
|
||||
- added `dict_to_list` and `dict_to_tuple`
|
||||
- added support for unicode
|
||||
- allowed chaining of objects like pickle does.
|
||||
|
||||
|
||||
:copyright: 2007-2008 by Armin Ronacher.
|
||||
license: BSD
|
||||
"""
|
||||
from StringIO import StringIO
|
||||
|
||||
__author__ = 'Armin Ronacher <armin.ronacher@active-4.com>'
|
||||
__version__ = '1.1'
|
||||
|
||||
|
||||
def dumps(data, charset='utf-8', errors='strict'):
|
||||
"""Return the PHP-serialized representation of the object as a string,
|
||||
instead of writing it to a file like `dump` does.
|
||||
"""
|
||||
def _serialize(obj, keypos):
|
||||
if keypos:
|
||||
if isinstance(obj, (int, long, float, bool)):
|
||||
return 'i:%i;' % obj
|
||||
if isinstance(obj, basestring):
|
||||
if isinstance(obj, unicode):
|
||||
obj = obj.encode(charset, errors)
|
||||
return 's:%i:"%s";' % (len(obj), obj)
|
||||
if obj is None:
|
||||
return 's:0:"";'
|
||||
raise TypeError('can\'t serialize %r as key' % type(obj))
|
||||
else:
|
||||
if obj is None:
|
||||
return 'N;'
|
||||
if isinstance(obj, bool):
|
||||
return 'b:%i;' % obj
|
||||
if isinstance(obj, (int, long)):
|
||||
return 'i:%s;' % obj
|
||||
if isinstance(obj, float):
|
||||
return 'd:%s;' % obj
|
||||
if isinstance(obj, basestring):
|
||||
if isinstance(obj, unicode):
|
||||
obj = obj.encode(charset, errors)
|
||||
return 's:%i:"%s";' % (len(obj), obj)
|
||||
if isinstance(obj, (list, tuple, dict)):
|
||||
out = []
|
||||
if isinstance(obj, dict):
|
||||
iterable = obj.iteritems()
|
||||
else:
|
||||
iterable = enumerate(obj)
|
||||
for key, value in iterable:
|
||||
out.append(_serialize(key, True))
|
||||
out.append(_serialize(value, False))
|
||||
return 'a:%i:{%s}' % (len(obj), ''.join(out))
|
||||
raise TypeError('can\'t serialize %r' % type(obj))
|
||||
return _serialize(data, False)
|
||||
|
||||
|
||||
def load(fp, charset='utf-8', errors='strict', decode_strings=False):
|
||||
"""Read a string from the open file object `fp` and interpret it as a
|
||||
data stream of PHP-serialized objects, reconstructing and returning
|
||||
the original object hierarchy.
|
||||
|
||||
`fp` must provide a `read()` method that takes an integer argument. Both
|
||||
method should return strings. Thus `fp` can be a file object opened for
|
||||
reading, a `StringIO` object, or any other custom object that meets this
|
||||
interface.
|
||||
|
||||
`load` will read exactly one object from the stream. See the docstring of
|
||||
the module for this chained behavior.
|
||||
"""
|
||||
def _expect(e):
|
||||
v = fp.read(len(e))
|
||||
if v != e:
|
||||
raise ValueError('failed expectation, expected %r got %r' % (e, v))
|
||||
|
||||
def _read_until(delim):
|
||||
buf = []
|
||||
while 1:
|
||||
char = fp.read(1)
|
||||
if char == delim:
|
||||
break
|
||||
elif not char:
|
||||
raise ValueError('unexpected end of stream')
|
||||
buf.append(char)
|
||||
return ''.join(buf)
|
||||
|
||||
def _unserialize():
|
||||
type_ = fp.read(1).lower()
|
||||
if type_ == 'n':
|
||||
_expect(';')
|
||||
return None
|
||||
if type_ in 'idb':
|
||||
_expect(':')
|
||||
data = _read_until(';')
|
||||
if type_ == 'i':
|
||||
return int(data)
|
||||
if type_ == 'd':
|
||||
return float(data)
|
||||
return int(data) != 0
|
||||
if type_ == 's':
|
||||
_expect(':')
|
||||
length = int(_read_until(':'))
|
||||
_expect('"')
|
||||
data = fp.read(length)
|
||||
_expect('"')
|
||||
if decode_strings:
|
||||
data = data.decode(charset, errors)
|
||||
_expect(';')
|
||||
return data
|
||||
if type_ == 'a':
|
||||
_expect(':')
|
||||
items = int(_read_until(':')) * 2
|
||||
_expect('{')
|
||||
result = {}
|
||||
last_item = Ellipsis
|
||||
for idx in xrange(items):
|
||||
item = _unserialize()
|
||||
if last_item is Ellipsis:
|
||||
last_item = item
|
||||
else:
|
||||
result[last_item] = item
|
||||
last_item = Ellipsis
|
||||
_expect('}')
|
||||
return result
|
||||
raise ValueError('unexpected opcode')
|
||||
|
||||
return _unserialize()
|
||||
|
||||
|
||||
def loads(data, charset='utf-8', errors='strict', decode_strings=False):
|
||||
"""Read a PHP-serialized object hierarchy from a string. Characters in the
|
||||
string past the object's representation are ignored.
|
||||
"""
|
||||
return load(StringIO(data), charset, errors, decode_strings)
|
||||
|
||||
|
||||
def dump(data, fp, charset='utf-8', errors='strict'):
|
||||
"""Write a PHP-serialized representation of obj to the open file object
|
||||
`fp`. Unicode strings are encoded to `charset` with the error handling
|
||||
of `errors`.
|
||||
|
||||
`fp` must have a `write()` method that accepts a single string argument.
|
||||
It can thus be a file object opened for writing, a `StringIO` object, or
|
||||
any other custom object that meets this interface.
|
||||
"""
|
||||
fp.write(dumps(data, charset, errors))
|
||||
|
||||
|
||||
def dict_to_list(d):
|
||||
"""Converts an ordered dict into a list."""
|
||||
try:
|
||||
return [d[x] for x in xrange(len(d))]
|
||||
except KeyError:
|
||||
raise ValueError('dict is not a sequence')
|
||||
|
||||
|
||||
def dict_to_tuple(d):
|
||||
"""Converts an ordered dict into a tuple."""
|
||||
return tuple(dict_to_list(d))
|
||||
|
||||
|
||||
serialize = dumps
|
||||
unserialize = loads
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
|
@ -1,11 +1,16 @@
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.utils import translation
|
||||
from django.conf import settings as global_settings
|
||||
from forum import settings
|
||||
|
||||
from forum import settings as forum_settings
|
||||
|
||||
class LastLoginMiddleware(object):
|
||||
def process_request(self, request):
|
||||
cache.set(str(request.user.id), True, forum_settings.USER_ONLINE_TIMEOUT)
|
||||
if request.user.is_authenticated():
|
||||
cache.set(str(request.user.id), True, forum_settings.USER_ONLINE_TIMEOUT)
|
||||
|
||||
class ForumMiddleware(object):
|
||||
def process_request(self, request):
|
||||
|
@ -21,3 +26,24 @@ class ForumMiddleware(object):
|
|||
request.session['django_language'] = profile.language
|
||||
translation.activate(profile.language)
|
||||
request.LANGUAGE_CODE = translation.get_language()
|
||||
|
||||
class UsersOnline(object):
|
||||
def process_request(self, request):
|
||||
now = datetime.now()
|
||||
delta = now - timedelta(minutes=settings.USER_ONLINE_TIMEOUT)
|
||||
|
||||
if request.user.is_authenticated():
|
||||
users_online = cache.get('users_online', {})
|
||||
users_online[request.user.id] = now
|
||||
for user_id in users_online:
|
||||
if users_online[user_id] < delta:
|
||||
del users_online[user_id]
|
||||
cache.set('users_online', users_online, 60*60*24)
|
||||
else:
|
||||
guests_online = cache.get('guests_online', {})
|
||||
guest_sid = request.COOKIES.get(global_settings.SESSION_COOKIE_NAME, '')
|
||||
guests_online[guest_sid] = now
|
||||
for guest_id in guests_online:
|
||||
if guests_online[guest_id] < delta:
|
||||
del guests_online[guest_id]
|
||||
cache.set('guests_online', guests_online, 60*60*24)
|
|
@ -21,7 +21,7 @@ TAGLINE = get('TAGLINE', 'Django based forum engine')
|
|||
DEFAULT_MARKUP = get('DEFAULT_MARKUP', 'bbcode')
|
||||
NOTICE = get('NOTICE', '')
|
||||
HOST = get('HOST', 'localhost:8000')
|
||||
USER_ONLINE_TIMEOUT = get('USER_ONLINE_TIMEOUT', 30)
|
||||
USER_ONLINE_TIMEOUT = get('USER_ONLINE_TIMEOUT', 15)
|
||||
EMAIL_DEBUG = get('FORUM_EMAIL_DEBUG', False)
|
||||
|
||||
# GRAVATAR Extension
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<li id="navuserlist"><a href="{% url forum_users %}">{% trans "User list" %}</a></li>
|
||||
<li id="navsearch"><a href="{% url search %}">{% trans "Search" %}</a></li>
|
||||
{% if user.is_superuser %}
|
||||
<li id="navadmin"><a href="{% url admincp "." %}">{% trans "Administration" %}</a></li>
|
||||
<li id="navadmin"><a href="{% url admin_index %}">{% trans "Administration" %}</a></li>
|
||||
{% endif %}
|
||||
{% if user.is_authenticated %}
|
||||
<li id="navprofile"><a href="{% url forum_profile request.user %}">{% trans "Profile" %}</a></li>
|
||||
|
@ -43,7 +43,7 @@
|
|||
<li>{% trans "You are not logged in." %}</li>
|
||||
{% endif %}
|
||||
{% if user.is_superuser and reports %}
|
||||
<li class="reportlink"><strong><a href="{% url admincp "." %}">{% trans "There are new reports" %} ({% new_reports %})</a></strong></li>
|
||||
<li class="reportlink"><strong><a href="{% url admin_index %}">{% trans "There are new reports" %} ({% new_reports %})</a></strong></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if user.is_authenticated %}
|
||||
|
|
|
@ -13,8 +13,12 @@ from django.core.cache import cache
|
|||
from django.utils import translation
|
||||
|
||||
from forum.util import render_to, paged, build_form, paginate, set_language
|
||||
from forum.models import Category, Forum, Topic, Post, Profile, Read, Reputation, Report, PrivateMessage
|
||||
from forum.forms import AddPostForm, EditPostForm, UserSearchForm, PostSearchForm, ReputationForm, MailToForm, EssentialsProfileForm, PersonalProfileForm, MessagingProfileForm, PersonalityProfileForm, DisplayProfileForm, PrivacyProfileForm, ReportForm, UploadAvatarForm, CreatePMForm
|
||||
from forum.models import Category, Forum, Topic, Post, Profile, Read,\
|
||||
Reputation, Report, PrivateMessage
|
||||
from forum.forms import AddPostForm, EditPostForm, UserSearchForm,\
|
||||
PostSearchForm, ReputationForm, MailToForm, EssentialsProfileForm,\
|
||||
PersonalProfileForm, MessagingProfileForm, PersonalityProfileForm,\
|
||||
DisplayProfileForm, PrivacyProfileForm, ReportForm, UploadAvatarForm, CreatePMForm
|
||||
from forum.markups import mypostmarkup
|
||||
from forum.templatetags import forum_extras
|
||||
from forum import settings as forum_settings
|
||||
|
@ -23,13 +27,12 @@ from forum.index import post_indexer
|
|||
|
||||
@render_to('forum/index.html')
|
||||
def index(request, full=True):
|
||||
users_online = []
|
||||
#TODO: refactoring
|
||||
for user in User.objects.all():
|
||||
if cache.get(str(user.id)):
|
||||
users_online.append(user)
|
||||
guest_count = len(cache._cache) - len(users_online)
|
||||
|
||||
users_cached = cache.get('users_online', {})
|
||||
users_online = users_cached and User.objects.filter(id__in = users_cached.keys()) or []
|
||||
guests_cached = cache.get('guests_online', {})
|
||||
guest_count = len(guests_cached)
|
||||
users_count = len(users_online)
|
||||
#users_total_online = guest_count + users_count
|
||||
cats = {}
|
||||
forums = {}
|
||||
|
||||
|
@ -47,7 +50,7 @@ def index(request, full=True):
|
|||
'topics': Topic.objects.count(),
|
||||
'users': User.objects.count(),
|
||||
'users_online': users_online,
|
||||
'online_count': len(users_online),
|
||||
'online_count': users_count,
|
||||
'guest_count': guest_count,
|
||||
'last_user': User.objects.order_by('-date_joined')[0],
|
||||
}
|
||||
|
@ -57,7 +60,7 @@ def index(request, full=True):
|
|||
'topics': Topic.objects.count(),
|
||||
'users': User.objects.count(),
|
||||
'users_online': users_online,
|
||||
'online_count': len(users_online),
|
||||
'online_count': users_count,
|
||||
'guest_count': guest_count,
|
||||
'last_user': User.objects.order_by('-date_joined')[0],
|
||||
}, 'forum/lofi/index.html'
|
||||
|
|
70
fill.py
70
fill.py
|
@ -1,70 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
This module fill project database with objects described in YAML file.
|
||||
"""
|
||||
|
||||
import os
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
|
||||
|
||||
import yaml
|
||||
import logging
|
||||
from itertools import chain
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
def parse():
|
||||
conf = yaml.load(open('init.ya').read())
|
||||
meta = conf.pop('meta')
|
||||
objects = {}
|
||||
models = {}
|
||||
|
||||
for model_name, path in meta['models'].iteritems():
|
||||
module = __import__(path, globals(), locals(), [model_name])
|
||||
model = getattr(module, model_name)
|
||||
models[model_name] = model
|
||||
|
||||
for model_name in meta['order']:
|
||||
model = models[model_name]
|
||||
|
||||
logging.debug('Deleting all %s instances' % model_name)
|
||||
model.objects.all().delete()
|
||||
|
||||
defaults = meta['defaults'].get(model_name, {})
|
||||
|
||||
for item in conf[model_name]:
|
||||
if 'ref' in item:
|
||||
ref = item.pop('ref')
|
||||
else:
|
||||
ref = None
|
||||
|
||||
obj = model()
|
||||
m2m = {}
|
||||
|
||||
for key, value in chain(item.iteritems(), defaults.iteritems()):
|
||||
if isinstance(obj, User) and key == 'password':
|
||||
obj.set_password(value)
|
||||
elif isinstance(value, dict):
|
||||
fk_model, fk_ref = value.items()[0]
|
||||
setattr(obj, key, objects[fk_model][fk_ref])
|
||||
elif isinstance(value, (dict, list)):
|
||||
for m2m_value in value:
|
||||
fk_model, fk_ref = m2m_value.items()[0]
|
||||
m2m.setdefault(key, []).append(objects[fk_model][fk_ref])
|
||||
else:
|
||||
setattr(obj, key, value)
|
||||
obj.save()
|
||||
|
||||
logging.debug(u'New %s instance: %s' % (model_name, obj))
|
||||
|
||||
for key, values in m2m.iteritems():
|
||||
setattr(obj, key, values)
|
||||
#logging.debug('New m2m records %s' % values)
|
||||
|
||||
if ref:
|
||||
objects.setdefault(model_name, {})[ref] = obj
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
parse()
|
|
@ -3,10 +3,7 @@ import os.path
|
|||
import sys
|
||||
|
||||
PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
|
||||
DEVELOPMENT = True
|
||||
|
||||
if DEVELOPMENT:
|
||||
sys.path.append(os.path.join(PROJECT_ROOT, 'apps'))
|
||||
sys.path.append(os.path.join(PROJECT_ROOT, 'apps'))
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
@ -92,6 +89,7 @@ MIDDLEWARE_CLASSES = (
|
|||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'account.middleware.AuthKeyMiddleware',
|
||||
'forum.middleware.LastLoginMiddleware',
|
||||
'forum.middleware.UsersOnline',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'urls'
|
||||
|
@ -115,7 +113,6 @@ INSTALLED_APPS = (
|
|||
'captcha',
|
||||
'forum',
|
||||
'djapian',
|
||||
'django_evolution',
|
||||
)
|
||||
|
||||
FORCE_SCRIPT_NAME = ''
|
||||
|
|
2
urls.py
2
urls.py
|
@ -26,7 +26,7 @@ sitemaps = {
|
|||
|
||||
urlpatterns = patterns('',
|
||||
# Admin
|
||||
url(r'^admin/(.*)', admin.site.root, name='admincp'),
|
||||
(r'^admin/', include(admin.site.urls)),
|
||||
|
||||
# Sitemap
|
||||
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
|
||||
|
|
Reference in a new issue