This commit is contained in:
slav0nic 2009-04-07 15:28:41 +03:00
commit ca740fef99
10 changed files with 49 additions and 348 deletions

View file

@ -5,6 +5,8 @@ local_settings.py
.pydevproject
.project
debug_toolbar
django
djapian_db
*.db
*.json
*.log

View file

@ -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()

View file

@ -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)

View file

@ -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

View file

@ -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 %}

View file

@ -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
View file

@ -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()

View file

@ -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 = ''

View file

@ -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}),