<reponame>igeeker/v2ex
#!/usr/bin/env python
# coding=utf-8

import base64
import os
import re
import time
import datetime
import hashlib
import logging
import string
import StringIO
import random
import math

from google.appengine.ext import webapp
from google.appengine.api import memcache
from google.appengine.api import images
from google.appengine.ext import db
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template

from v2ex.babel import Avatar
from v2ex.babel import Member
from v2ex.babel import Counter
from v2ex.babel import Section
from v2ex.babel import Node
from v2ex.babel import Site
from v2ex.babel import Minisite
from v2ex.babel import Page

from v2ex.babel import SYSTEM_VERSION

from v2ex.babel.security import *
from v2ex.babel.ext.cookies import Cookies
from v2ex.babel.ua import *
from v2ex.babel.da import *
from v2ex.babel.l10n import *

from v2ex.babel.handlers import BaseHandler

template.register_template_library('v2ex.templatetags.filters')

import config

class BackstageHomeHandler(webapp.RequestHandler):
    def get(self):
        site = GetSite()
        browser = detect(self.request)
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values = {}
        template_values['l10n'] = l10n
        template_values['site'] = site
        template_values['rnd'] = random.randrange(1, 100)
        template_values['system_version'] = SYSTEM_VERSION
        template_values['member'] = member
        template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8')
        member_total = memcache.get('member_total')
        if member_total is None:
            q3 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'member.total'")
            if (q3.count() > 0):
                member_total = q3[0].value
            else:
                member_total = 0
            memcache.set('member_total', member_total, 600)
        template_values['member_total'] = member_total
        topic_total = memcache.get('topic_total')
        if topic_total is None:
            q4 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'topic.total'")
            if (q4.count() > 0):
                topic_total = q4[0].value
            else:
                topic_total = 0
            memcache.set('topic_total', topic_total, 600)
        template_values['topic_total'] = topic_total
        reply_total = memcache.get('reply_total')
        if reply_total is None:
            q5 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'reply.total'")
            if (q5.count() > 0):
                reply_total = q5[0].value
            else:
                reply_total = 0
            memcache.set('reply_total', reply_total, 600)
        template_values['reply_total'] = reply_total
        if (member):
            if (member.level == 0):
                q = db.GqlQuery("SELECT * FROM Section ORDER BY nodes DESC")
                template_values['sections'] = q
                q2 = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT 5")
                template_values['latest_members'] = q2
                q3 = db.GqlQuery("SELECT * FROM Minisite ORDER BY created DESC")
                template_values['minisites'] = q3
                q4 = db.GqlQuery("SELECT * FROM Node ORDER BY last_modified DESC LIMIT 8")
                template_values['latest_nodes'] = q4
                if browser['ios']:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_home.html')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_home.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
            
class BackstageNewMinisiteHandler(webapp.RequestHandler):
    def get(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['page_title'] = site.title + u' › 添加新站点'
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):    
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_minisite.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['page_title'] = site.title + u' › 添加新站点'
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                errors = 0
                # Verification: name
                minisite_name_error = 0
                minisite_name_error_messages = ['',
                    u'请输入站点名',
                    u'站点名长度不能超过 32 个字符',
                    u'站点名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个站点名已经存在了']
                minisite_name = self.request.get('name').strip().lower()
                if (len(minisite_name) == 0):
                    errors = errors + 1
                    minisite_name_error = 1
                else:
                    if (len(minisite_name) > 32):
                        errors = errors + 1
                        minisite_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', minisite_name)):
                            q = db.GqlQuery('SELECT __key__ FROM Minisite WHERE name = :1', minisite_name.lower())
                            if (q.count() > 0):
                                errors = errors + 1
                                minisite_name_error = 4
                        else:
                            errors = errors + 1
                            minisite_name_error = 3
                template_values['minisite_name'] = minisite_name
                template_values['minisite_name_error'] = minisite_name_error
                template_values['minisite_name_error_message'] = minisite_name_error_messages[minisite_name_error]
                # Verification: title
                minisite_title_error = 0
                minisite_title_error_messages = ['',
                    u'请输入站点标题',
                    u'站点标题长度不能超过 32 个字符'
                ]
                minisite_title = self.request.get('title').strip()
                if (len(minisite_title) == 0):
                    errors = errors + 1
                    minisite_title_error = 1
                else:
                    if (len(minisite_title) > 32):
                        errors = errors + 1
                        minisite_title_error = 2
                template_values['minisite_title'] = minisite_title
                template_values['minisite_title_error'] = minisite_title_error
                template_values['minisite_title_error_message'] = minisite_title_error_messages[minisite_title_error]
                # Verification: description
                minisite_description_error = 0
                minisite_description_error_messages = ['',
                    u'请输入站点描述',
                    u'站点描述长度不能超过 2000 个字符'
                ]
                minisite_description = self.request.get('description').strip()
                if (len(minisite_description) == 0):
                    errors = errors + 1
                    minisite_description_error = 1
                else:
                    if (len(minisite_description) > 2000):
                        errors = errors + 1
                        minisite_description_error = 2
                template_values['minisite_description'] = minisite_description
                template_values['minisite_description_error'] = minisite_description_error
                template_values['minisite_description_error_message'] = minisite_description_error_messages[minisite_description_error]
                template_values['errors'] = errors
                if (errors == 0):
                    minisite = Minisite()
                    q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'minisite.max')
                    if (q.count() == 1):
                        counter = q[0]
                        counter.value = counter.value + 1
                    else:
                        counter = Counter()
                        counter.name = 'minisite.max'
                        counter.value = 1
                    minisite.num = counter.value
                    minisite.name = minisite_name
                    minisite.title = minisite_title
                    minisite.description = minisite_description
                    minisite.put()
                    counter.put()
                    self.redirect('/backstage')
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_minisite.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
            
class BackstageMinisiteHandler(webapp.RequestHandler):
    def get(self, minisite_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['page_title'] = site.title + u' › Minisite'
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                minisite = GetKindByName('Minisite', minisite_name)
                if minisite is not False:
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title
                    q = db.GqlQuery("SELECT * FROM Page WHERE minisite = :1 ORDER BY weight ASC", minisite)
                    template_values['pages'] = q
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_minisite.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageNewPageHandler(webapp.RequestHandler):
    def get(self, minisite_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                minisite = GetKindByName('Minisite', minisite_name)
                if minisite is not False:
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › 添加新页面'
                    template_values['page_content_type'] = 'text/html;charset=utf-8'
                    template_values['page_weight'] = 0
                    template_values['page_mode'] = 0
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_page.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

    def post(self, minisite_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                minisite = GetKindByName('Minisite', minisite_name)
                if minisite is False:
                    self.redirect('/backstage')
                else:
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › 添加新页面'
                    errors = 0
                    # Verification: name
                    page_name_error = 0
                    page_name_error_messages = ['',
                        u'请输入页面名',
                        u'页面名长度不能超过 64 个字符',
                        u'页面名只能由 a-Z 0-9 及 . - _ 组成',
                        u'抱歉这个页面名已经存在了']
                    page_name = self.request.get('name').strip().lower()
                    if (len(page_name) == 0):
                        errors = errors + 1
                        page_name_error = 1
                    else:
                        if (len(page_name) > 64):
                            errors = errors + 1
                            page_name_error = 2
                        else:
                            if (re.search('^[a-zA-Z0-9\-\_\.]+$', page_name)):
                                q = db.GqlQuery('SELECT * FROM Page WHERE name = :1', page_name.lower())
                                if (q.count() > 0):
                                    if q[0].minisite.name == minisite.name:
                                        errors = errors + 1
                                        page_name_error = 4
                            else:
                                errors = errors + 1
                                page_name_error = 3
                    template_values['page_name'] = page_name
                    template_values['page_name_error'] = page_name_error
                    template_values['page_name_error_message'] = page_name_error_messages[page_name_error]
                    # Verification: title
                    page_t_error = 0
                    page_t_error_messages = ['',
                        u'请输入页面标题',
                        u'页面标题长度不能超过 100 个字符'
                    ]
                    page_t = self.request.get('t').strip()
                    if (len(page_t) == 0):
                        errors = errors + 1
                        page_t_error = 1
                    else:
                        if (len(page_t) > 100):
                            errors = errors + 1
                            page_t_error = 2
                    template_values['page_t'] = page_t
                    template_values['page_t_error'] = page_t_error
                    template_values['page_t_error_message'] = page_t_error_messages[page_t_error]
                    # Verification: content
                    page_content_error = 0
                    page_content_error_messages = ['',
                        u'请输入页面内容',
                        u'页面内容长度不能超过 200000 个字符'
                    ]
                    page_content = self.request.get('content').strip()
                    if (len(page_content) == 0):
                        errors = errors + 1
                        page_content_error = 1
                    else:
                        if (len(page_content) > 200000):
                            errors = errors + 1
                            page_content_error = 2
                    template_values['page_content'] = page_content
                    template_values['page_content_error'] = page_content_error
                    template_values['page_content_error_message'] = page_content_error_messages[page_content_error]
                    # Verification: mode
                    page_mode = 0
                    page_mode = self.request.get('mode').strip()
                    if page_mode == '1':
                        page_mode = 1
                    else:
                        page_mode = 0
                    # Verification: content_type
                    page_content_type = self.request.get('content_type').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 'text/html;charset=utf-8'
                    else:
                        if (len(page_content_type) > 40):
                            page_content_type = 'text/html;charset=utf-8'
                    template_values['page_content_type'] = page_content_type
                    # Verification: weight
                    page_weight = self.request.get('weight').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 0
                    else:
                        if (len(page_weight) > 9):
                            page_weight = 0
                        else:
                            try:
                                page_weight = int(page_weight)
                            except:
                                page_weight = 0
                    template_values['page_weight'] = page_weight
                    template_values['errors'] = errors
                    if (errors == 0):
                        page = Page(parent=minisite)
                        q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'page.max')
                        if (q.count() == 1):
                            counter = q[0]
                            counter.value = counter.value + 1
                        else:
                            counter = Counter()
                            counter.name = 'page.max'
                            counter.value = 1
                        q2 = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'page.total')
                        if (q2.count() == 1):
                            counter2 = q[0]
                            counter2.value = counter.value + 1
                        else:
                            counter2 = Counter()
                            counter2.name = 'page.total'
                            counter2.value = 1
                        page.num = counter.value
                        page.name = page_name
                        page.title = page_t
                        page.content = page_content
                        if page_mode == 1:
                            from django.template import Context, Template
                            t = Template(page_content)
                            c = Context({"site" : site, "minisite" : page.minisite, "page" : page})
                            output = t.render(c)
                            page.content_rendered = output
                        else:
                            page.content_rendered = page_content
                        page.content_type = page_content_type
                        page.weight = page_weight
                        page.mode = page_mode
                        page.minisite = minisite
                        page.put()
                        counter.put()
                        counter2.put()
                        minisite.pages = minisite.pages + 1
                        minisite.put()
                        memcache.delete('Minisite_' + str(minisite.num))
                        memcache.delete('Minisite::' + str(minisite.name))
                        self.redirect('/backstage/minisite/' + minisite.name)
                    else:    
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_page.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageRemoveMinisiteHandler(webapp.RequestHandler):
    def get(self, minisite_key):
        member = CheckAuth(self)
        if member:
            if member.level == 0:
                minisite = db.get(db.Key(minisite_key))
                if minisite:
                    # Delete all contents
                    pages = db.GqlQuery("SELECT * FROM Page WHERE minisite = :1", minisite)
                    for page in pages:
                        memcache.delete('Page_' + str(page.num))
                        memcache.delete('Page::' + str(page.name))
                        memcache.delete(minisite.name + '/' + page.name)
                        page.delete()
                    minisite.pages = 0
                    minisite.put()
                    # Delete the minisite
                    memcache.delete('Minisite_' + str(minisite.num))
                    memcache.delete('Minisite::' + str(minisite.name))
                    minisite.delete()
                    self.redirect('/backstage')
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstagePageHandler(webapp.RequestHandler):
    def get(self, page_key):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                page = db.get(db.Key(page_key))
                if page:
                    minisite = page.minisite
                    template_values['page'] = page
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › ' + page.title + u' › 编辑'
                    template_values['page_name'] = page.name
                    template_values['page_t'] = page.title
                    template_values['page_content'] = page.content
                    template_values['page_content_type'] = page.content_type
                    template_values['page_mode'] = page.mode
                    template_values['page_weight'] = page.weight
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_page.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

    def post(self, page_key):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                page = db.get(db.Key(page_key))
                if page:
                    minisite = page.minisite
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › 添加新页面'
                    errors = 0
                    # Verification: name
                    page_name_error = 0
                    page_name_error_messages = ['',
                        u'请输入页面名',
                        u'页面名长度不能超过 64 个字符',
                        u'页面名只能由 a-Z 0-9 及 . - _ 组成',
                        u'抱歉这个页面名已经存在了']
                    page_name = self.request.get('name').strip().lower()
                    if (len(page_name) == 0):
                        errors = errors + 1
                        page_name_error = 1
                    else:
                        if (len(page_name) > 64):
                            errors = errors + 1
                            page_name_error = 2
                        else:
                            if (re.search('^[a-zA-Z0-9\-\_\.]+$', page_name)):
                                q = db.GqlQuery('SELECT * FROM Page WHERE name = :1 AND minisite = :2', page_name.lower(), page.minisite)
                                if (q.count() > 0):
                                    if q[0].num != page.num:
                                        errors = errors + 1
                                        page_name_error = 4
                            else:
                                errors = errors + 1
                                page_name_error = 3
                    template_values['page_name'] = page_name
                    template_values['page_name_error'] = page_name_error
                    template_values['page_name_error_message'] = page_name_error_messages[page_name_error]
                    # Verification: title
                    page_t_error = 0
                    page_t_error_messages = ['',
                        u'请输入页面标题',
                        u'页面标题长度不能超过 100 个字符'
                    ]
                    page_t = self.request.get('t').strip()
                    if (len(page_t) == 0):
                        errors = errors + 1
                        page_t_error = 1
                    else:
                        if (len(page_t) > 100):
                            errors = errors + 1
                            page_t_error = 2
                    template_values['page_t'] = page_t
                    template_values['page_t_error'] = page_t_error
                    template_values['page_t_error_message'] = page_t_error_messages[page_t_error]
                    # Verification: content
                    page_content_error = 0
                    page_content_error_messages = ['',
                        u'请输入页面内容',
                        u'页面内容长度不能超过 200000 个字符'
                    ]
                    page_content = self.request.get('content').strip()
                    if (len(page_content) == 0):
                        errors = errors + 1
                        page_content_error = 1
                    else:
                        if (len(page_content) > 200000):
                            errors = errors + 1
                            page_content_error = 2
                    template_values['page_content'] = page_content
                    template_values['page_content_error'] = page_content_error
                    template_values['page_content_error_message'] = page_content_error_messages[page_content_error]
                    # Verification: mode
                    page_mode = 0
                    page_mode = self.request.get('mode').strip()
                    if page_mode == '1':
                        page_mode = 1
                    else:
                        page_mode = 0
                    # Verification: content_type
                    page_content_type = self.request.get('content_type').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 'text/html;charset=utf-8'
                    else:
                        if (len(page_content_type) > 40):
                            page_content_type = 'text/html;charset=utf-8'
                    template_values['page_content_type'] = page_content_type
                    # Verification: weight
                    page_weight = self.request.get('weight').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 0
                    else:
                        if (len(page_weight) > 9):
                            page_weight = 0
                        else:
                            try:
                                page_weight = int(page_weight)
                            except:
                                page_weight = 0
                    template_values['page_weight'] = page_weight
                    template_values['errors'] = errors
                    if (errors == 0):
                        page.name = page_name
                        page.title = page_t
                        page.content = page_content
                        if page.mode == 1:
                            from django.template import Context, Template
                            t = Template(page_content)
                            c = Context({"site" : site, "minisite" : page.minisite, "page" : page})
                            output = t.render(c)
                            page.content_rendered = output
                        else:
                            page.content_rendered = page_content
                        page.content_type = page_content_type
                        page.mode = page_mode
                        page.weight = page_weight
                        page.put()
                        memcache.delete('Page_' + str(page.num))
                        memcache.delete('Page::' + str(page.name))
                        memcache.delete(minisite.name + '/' + page.name)
                        self.redirect('/backstage/minisite/' + minisite.name)
                    else:    
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_page.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
class BackstageRemovePageHandler(webapp.RequestHandler):
    def get(self, page_key):
        member = CheckAuth(self)
        if member:
            if member.level == 0:
                page = db.get(db.Key(page_key))
                if page:
                    memcache.delete('Page_' + str(page.num))
                    memcache.delete('Page::' + str(page.name))
                    memcache.delete(page.minisite.name + '/' + page.name)
                    minisite = page.minisite
                    page.delete()
                    minisite.pages = minisite.pages - 1
                    minisite.put()
                    self.redirect('/backstage/minisite/' + minisite.name)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageNewSectionHandler(webapp.RequestHandler):
    def get(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):    
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_section.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                errors = 0
                # Verification: name
                section_name_error = 0
                section_name_error_messages = ['',
                    u'请输入区域名',
                    u'区域名长度不能超过 32 个字符',
                    u'区域名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个区域名已经存在了']
                section_name = self.request.get('name').strip().lower()
                if (len(section_name) == 0):
                    errors = errors + 1
                    section_name_error = 1
                else:
                    if (len(section_name) > 32):
                        errors = errors + 1
                        section_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', section_name)):
                            q = db.GqlQuery('SELECT __key__ FROM Section WHERE name = :1', section_name.lower())
                            if (q.count() > 0):
                                errors = errors + 1
                                section_name_error = 4
                        else:
                            errors = errors + 1
                            section_name_error = 3
                template_values['section_name'] = section_name
                template_values['section_name_error'] = section_name_error
                template_values['section_name_error_message'] = section_name_error_messages[section_name_error]
                # Verification: title
                section_title_error = 0
                section_title_error_messages = ['',
                    u'请输入区域标题',
                    u'区域标题长度不能超过 32 个字符'
                ]
                section_title = self.request.get('title').strip()
                if (len(section_title) == 0):
                    errors = errors + 1
                    section_title_error = 1
                else:
                    if (len(section_title) > 32):
                        errors = errors + 1
                        section_title_error = 2
                template_values['section_title'] = section_title
                template_values['section_title_error'] = section_title_error
                template_values['section_title_error_message'] = section_title_error_messages[section_title_error]
                # Verification: title
                section_title_alternative_error = 0
                section_title_alternative_error_messages = ['',
                    u'请输入区域副标题',
                    u'区域标题长度不能超过 32 个字符'
                ]
                section_title_alternative = self.request.get('title_alternative').strip()
                if (len(section_title_alternative) == 0):
                    errors = errors + 1
                    section_title_alternative_error = 1
                else:
                    if (len(section_title_alternative) > 32):
                        errors = errors + 1
                        section_title_alternative_error = 2
                template_values['section_title_alternative'] = section_title_alternative
                template_values['section_title_alternative_error'] = section_title_alternative_error
                template_values['section_title_alternative_error_message'] = section_title_alternative_error_messages[section_title_alternative_error]
                template_values['errors'] = errors
                if (errors == 0):
                    section = Section()
                    q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'section.max')
                    if (q.count() == 1):
                        counter = q[0]
                        counter.value = counter.value + 1
                    else:
                        counter = Counter()
                        counter.name = 'section.max'
                        counter.value = 1
                    section.num = counter.value
                    section.name = section_name
                    section.title = section_title
                    section.title_alternative = section_title_alternative
                    section.put()
                    counter.put()
                    self.redirect('/backstage')
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_section.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageSectionHandler(webapp.RequestHandler):
    def get(self, section_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['rnd'] = random.randrange(1, 100)
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                template_values['member'] = member
                q = db.GqlQuery("SELECT * FROM Section WHERE name = :1", section_name)
                section = False
                if (q.count() == 1):
                    section = q[0]
                    template_values['section'] = section
                    template_values['page_title'] = site.title + u' › 后台 › ' + section.title
                    template_values['section_name'] = section.name
                    template_values['section_title'] = section.title
                    template_values['section_title_alternative'] = section.title_alternative
                    if section.header:
                        template_values['section_header'] = section.header
                    else:
                        template_values['section_header'] = ''
                    if section.footer:
                        template_values['section_footer'] = section.footer
                    else:
                        template_values['section_footer'] = ''
                else:
                    template_values['section'] = section
                if (section):
                    template_values['section'] = section
                    q2 = db.GqlQuery("SELECT * FROM Node WHERE section_num = :1 ORDER BY last_modified DESC LIMIT 10", section.num)
                    template_values['recent_modified'] = q2
                else:
                    template_values['nodes'] = False
                if browser['ios']:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_section.html')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_section.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self, section_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['rnd'] = random.randrange(1, 100)
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['member'] = member
                section = GetKindByName('Section', section_name)
                if section is not False:
                    template_values['section'] = section
                    errors = 0
                    # Verification: name
                    section_name_error = 0
                    section_name_error_messages = ['',
                        u'请输入区域名',
                        u'区域名长度不能超过 32 个字符',
                        u'区域名只能由 a-Z 0-9 及 - 和 _ 组成',
                        u'抱歉这个区域名已经存在了']
                    section_name = self.request.get('name').strip().lower()
                    if (len(section_name) == 0):
                        errors = errors + 1
                        section_name_error = 1
                    else:
                        if (len(section_name) > 32):
                            errors = errors + 1
                            section_name_error = 2
                        else:
                            if (re.search('^[a-zA-Z0-9\-\_]+$', section_name)):
                                q = db.GqlQuery('SELECT * FROM Section WHERE name = :1', section_name.lower())
                                if (q.count() > 0):
                                    for possible_conflict in q:
                                        if possible_conflict.num != section.num:
                                            errors = errors + 1
                                            section_name_error = 4
                            else:
                                errors = errors + 1
                                section_name_error = 3
                    template_values['section_name'] = section_name
                    template_values['section_name_error'] = section_name_error
                    template_values['section_name_error_message'] = section_name_error_messages[section_name_error]
                    # Verification: title
                    section_title_error = 0
                    section_title_error_messages = ['',
                        u'请输入区域标题',
                        u'区域标题长度不能超过 32 个字符'
                    ]
                    section_title = self.request.get('title').strip()
                    if (len(section_title) == 0):
                        errors = errors + 1
                        section_title_error = 1
                    else:
                        if (len(section_title) > 32):
                            errors = errors + 1
                            section_title_error = 2
                    template_values['section_title'] = section_title
                    template_values['section_title_error'] = section_title_error
                    template_values['section_title_error_message'] = section_title_error_messages[section_title_error]
                    # Verification: title_alternative
                    section_title_alternative_error = 0
                    section_title_alternative_error_messages = ['',
                        u'请输入区域副标题',
                        u'区域标题长度不能超过 32 个字符'
                    ]
                    section_title_alternative = self.request.get('title_alternative').strip()
                    if (len(section_title_alternative) == 0):
                        errors = errors + 1
                        section_title_alternative_error = 1
                    else:
                        if (len(section_title_alternative) > 32):
                            errors = errors + 1
                            section_title_alternative_error = 2
                    template_values['section_title_alternative'] = section_title_alternative
                    template_values['section_title_alternative_error'] = section_title_alternative_error
                    template_values['section_title_alternative_error_message'] = section_title_alternative_error_messages[section_title_alternative_error]
                    # Verification: header
                    section_header_error = 0
                    section_header_error_messages = ['',
                        u'区域头部信息不能超过 1000 个字符'
                    ]
                    section_header = self.request.get('header').strip()
                    if len(section_header) > 1000:
                        errors = errors + 1
                        section_header_error = 1
                    template_values['section_header'] = section_header
                    template_values['section_header_error'] = section_header_error
                    template_values['section_header_error_message'] = section_header_error_messages[section_header_error]
                    # Verification: footer
                    section_footer_error = 0
                    section_footer_error_messages = ['',
                        u'区域尾部信息不能超过 1000 个字符'
                    ]
                    section_footer = self.request.get('footer').strip()
                    if len(section_footer) > 1000:
                        errors = errors + 1
                        section_footer_error = 1
                    template_values['section_footer'] = section_footer
                    template_values['section_footer_error'] = section_footer_error
                    template_values['section_footer_error_message'] = section_footer_error_messages[section_footer_error]
                    template_values['errors'] = errors
                    if (errors == 0):
                        memcache.delete('Section::' + section.name)
                        section.name = section_name
                        section.title = section_title
                        section.title_alternative = section_title_alternative
                        section.header = section_header
                        section.footer = section_footer
                        section.put()
                        memcache.delete('Section_' + str(section.num))
                        memcache.delete('Section::' + section_name)
                        self.redirect('/backstage')
                    else:
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_section.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageNewNodeHandler(webapp.RequestHandler):
    def get(self, section_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                template_values['member'] = CheckAuth(self)
                q = db.GqlQuery("SELECT * FROM Section WHERE name = :1", section_name)
                if (q.count() == 1):
                    template_values['section'] = q[0]
                else:
                    template_values['section'] = False
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_node.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

    def post(self, section_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):        
                template_values['member'] = member
                section = False
                q = db.GqlQuery("SELECT * FROM Section WHERE name = :1", section_name)
                if (q.count() == 1):
                    section = q[0]
                    template_values['section'] = section
                else:
                    template_values['section'] = False
                errors = 0
                # Verification: name
                node_name_error = 0
                node_name_error_messages = ['',
                    u'请输入节点名',
                    u'节点名长度不能超过 32 个字符',
                    u'节点名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个节点名已经存在了']
                node_name = self.request.get('name').strip().lower()
                if (len(node_name) == 0):
                    errors = errors + 1
                    node_name_error = 1
                else:
                    if (len(node_name) > 32):
                        errors = errors + 1
                        node_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', node_name)):
                            q = db.GqlQuery('SELECT __key__ FROM Node WHERE name = :1', node_name.lower())
                            if (q.count() > 0):
                                errors = errors + 1
                                node_name_error = 4
                        else:
                            errors = errors + 1
                            node_name_error = 3
                template_values['node_name'] = node_name
                template_values['node_name_error'] = node_name_error
                template_values['node_name_error_message'] = node_name_error_messages[node_name_error]
                # Verification: title
                node_title_error = 0
                node_title_error_messages = ['',
                    u'请输入节点标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title = self.request.get('title').strip()
                if (len(node_title) == 0):
                    errors = errors + 1
                    node_title_error = 1
                else:
                    if (len(node_title) > 32):
                        errors = errors + 1
                        node_title_error = 2
                template_values['node_title'] = node_title
                template_values['node_title_error'] = node_title_error
                template_values['node_title_error_message'] = node_title_error_messages[node_title_error]
                # Verification: title
                node_title_alternative_error = 0
                node_title_alternative_error_messages = ['',
                    u'请输入节点副标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title_alternative = self.request.get('title_alternative').strip()
                if (len(node_title_alternative) == 0):
                    errors = errors + 1
                    node_title_alternative_error = 1
                else:
                    if (len(node_title_alternative) > 32):
                        errors = errors + 1
                        node_title_alternative_error = 2
                template_values['node_title_alternative'] = node_title_alternative
                template_values['node_title_alternative_error'] = node_title_alternative_error
                template_values['node_title_alternative_error_message'] = node_title_alternative_error_messages[node_title_alternative_error]
                template_values['errors'] = errors
                if (errors == 0):
                    node = Node()
                    q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'node.max')
                    if (q.count() == 1):
                        counter = q[0]
                        counter.value = counter.value + 1
                    else:
                        counter = Counter()
                        counter.name = 'node.max'
                        counter.value = 1
                    node.num = counter.value
                    node.section_num = section.num
                    node.name = node_name
                    node.title = node_title
                    node.title_alternative = node_title_alternative
                    node.put()
                    counter.put()
                    memcache.delete('index_categories')
                    memcache.delete('home_nodes_new')
                    self.redirect('/backstage/node/' + node.name)
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_node.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')


class BackstageNodeHandler(webapp.RequestHandler):
    def get(self, node_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                template_values['member'] = member
                q = db.GqlQuery("SELECT * FROM Node WHERE name = :1", node_name)
                if (q.count() == 1):
                    node = q[0]
                    if node.parent_node_name is None:
                        siblings = []
                    else:
                        siblings = db.GqlQuery("SELECT * FROM Node WHERE parent_node_name = :1 AND name != :2", node.parent_node_name, node.name)
                    template_values['siblings'] = siblings
                    template_values['node'] = node
                    template_values['node_name'] = node.name
                    template_values['node_title'] = node.title
                    template_values['node_title_alternative'] = q[0].title_alternative
                    if q[0].category is None:
                        template_values['node_category'] = ''
                    else:
                        template_values['node_category'] = q[0].category
                    if q[0].parent_node_name is None:
                        template_values['node_parent_node_name'] = ''
                    else:
                        template_values['node_parent_node_name'] = q[0].parent_node_name
                    if q[0].header is None:
                        template_values['node_header'] = ''
                    else:
                        template_values['node_header'] = q[0].header
                    if q[0].footer is None:
                        template_values['node_footer'] = ''
                    else:
                        template_values['node_footer'] = q[0].footer
                    if q[0].sidebar is None:
                        template_values['node_sidebar'] = ''
                    else:
                        template_values['node_sidebar'] = q[0].sidebar
                    if q[0].sidebar_ads is None:
                        template_values['node_sidebar_ads'] = ''
                    else:
                        template_values['node_sidebar_ads'] = q[0].sidebar_ads
                    template_values['node_topics'] = q[0].topics
                else:
                    template_values['node'] = False
                section = GetKindByNum('Section', node.section_num)
                template_values['section'] = section
                if section is not False:
                    template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + section.title + u' › ' + node.title
                if browser['ios']:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_node.html')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_node.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self, node_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):        
                template_values['member'] = member
                node = False
                q = db.GqlQuery("SELECT * FROM Node WHERE name = :1", node_name)
                if (q.count() == 1):
                    node = q[0]
                    template_values['node'] = q[0]
                    template_values['node_name'] = q[0].name
                    template_values['node_title'] = q[0].title
                    template_values['node_title_alternative'] = q[0].title_alternative
                    if q[0].category is None:
                        template_values['node_category'] = ''
                    else:
                        template_values['node_category'] = q[0].category
                    if q[0].parent_node_name is None:
                        template_values['node_parent_node_name'] = ''
                    else:
                        template_values['node_parent_node_name'] = q[0].parent_node_name
                    if q[0].header is None:
                        template_values['node_header'] = ''
                    else:
                        template_values['node_header'] = q[0].header
                    if q[0].footer is None:
                        template_values['node_footer'] = ''
                    else:
                        template_values['node_footer'] = q[0].footer
                    if q[0].sidebar is None:
                        template_values['node_sidebar'] = ''
                    else:
                        template_values['node_sidebar'] = q[0].sidebar
                    if q[0].sidebar_ads is None:
                        template_values['node_sidebar_ads'] = ''
                    else:
                        template_values['node_sidebar_ads'] = q[0].sidebar_ads
                    template_values['node_topics'] = q[0].topics
                else:
                    template_values['node'] = False
                section = False
                q2 = db.GqlQuery("SELECT * FROM Section WHERE num = :1", q[0].section_num)
                if (q2.count() == 1):
                    section = q2[0]
                    template_values['section'] = q2[0]
                else:
                    template_values['section'] = False
                if section is not False:
                    template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + section.title + u' › ' + node.title
                errors = 0
                # Verification: name
                node_name_error = 0
                node_name_error_messages = ['',
                    u'请输入节点名',
                    u'节点名长度不能超过 32 个字符',
                    u'节点名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个节点名已经存在了']
                node_name = self.request.get('name').strip().lower()
                if (len(node_name) == 0):
                    errors = errors + 1
                    node_name_error = 1
                else:
                    if (len(node_name) > 32):
                        errors = errors + 1
                        node_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', node_name)):
                            q = db.GqlQuery('SELECT * FROM Node WHERE name = :1 AND num != :2', node_name.lower(), node.num)
                            if (q.count() > 0):
                                errors = errors + 1
                                node_name_error = 4
                        else:
                            errors = errors + 1
                            node_name_error = 3
                template_values['node_name'] = node_name
                template_values['node_name_error'] = node_name_error
                template_values['node_name_error_message'] = node_name_error_messages[node_name_error]
                # Verification: title
                node_title_error = 0
                node_title_error_messages = ['',
                    u'请输入节点标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title = self.request.get('title').strip()
                if (len(node_title) == 0):
                    errors = errors + 1
                    node_title_error = 1
                else:
                    if (len(node_title) > 32):
                        errors = errors + 1
                        node_title_error = 2
                template_values['node_title'] = node_title
                template_values['node_title_error'] = node_title_error
                template_values['node_title_error_message'] = node_title_error_messages[node_title_error]
                # Verification: title_alternative
                node_title_alternative_error = 0
                node_title_alternative_error_messages = ['',
                    u'请输入节点副标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title_alternative = self.request.get('title_alternative').strip()
                if (len(node_title_alternative) == 0):
                    errors = errors + 1
                    node_title_alternative_error = 1
                else:
                    if (len(node_title_alternative) > 32):
                        errors = errors + 1
                        node_title_alternative_error = 2
                template_values['node_title_alternative'] = node_title_alternative
                template_values['node_title_alternative_error'] = node_title_alternative_error
                template_values['node_title_alternative_error_message'] = node_title_alternative_error_messages[node_title_alternative_error]
                # Verification: node_category
                node_category = self.request.get('category').strip()
                template_values['node_category'] = node_category
                # Verification: node_parent_node_name
                node_parent_node_name = self.request.get('parent_node_name').strip()
                template_values['node_parent_node_name'] = node_parent_node_name
                # Verification: node_header
                node_header = self.request.get('header').strip()
                template_values['node_header'] = node_header
                # Verification: node_footer
                node_footer = self.request.get('footer').strip()
                template_values['node_footer'] = node_footer
                # Verification: node_sidebar
                node_sidebar = self.request.get('sidebar').strip()
                template_values['node_sidebar'] = node_sidebar
                # Verification: node_sidebar_ads
                node_sidebar_ads = self.request.get('sidebar_ads').strip()
                template_values['node_sidebar_ads'] = node_sidebar_ads
                template_values['errors'] = errors
                if (errors == 0):
                    node.name = node_name
                    node.title = node_title
                    node.title_alternative = node_title_alternative
                    node.category = node_category
                    node.parent_node_name = node_parent_node_name
                    node.header = node_header
                    node.footer = node_footer
                    node.sidebar = node_sidebar
                    node.sidebar_ads = node_sidebar_ads
                    node.put()
                    memcache.delete('Node_' + str(node.num))
                    memcache.delete('Node::' + node.name)
                    memcache.delete('index_categories')
                    memcache.delete('home_nodes_new')
                    self.redirect('/backstage/section/' + section.name)
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_node.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')


class BackstageNodeAvatarHandler(BaseHandler):
    def get(self, node_name):
        self.redirect('/backstage/node/' + node_name)
    
    def post(self, node_name):
        if self.member:
            if self.member.level == 0:
                node = GetKindByName('Node', node_name)
                if node is None:
                    return self.redirect('/backstage')
                dest = '/backstage/node/' + node.name
                timestamp = str(int(time.time()))
                try:
                    avatar = self.request.get('avatar')
                except:
                    return self.redirect(dest)
                if avatar is None:
                    return self.redirect(dest)
                avatar_len = len(avatar)
                if avatar_len == 0:
                    return self.redirect(dest)
                avatar_73 = images.resize(avatar, 73, 73)
                avatar_48 = images.resize(avatar, 48, 48)
                avatar_24 = images.resize(avatar, 24, 24)
                # Large 73x73
                q1 = db.GqlQuery("SELECT * FROM Avatar WHERE name = :1", 'node_' + str(node.num) + '_large')
                if (q1.count() == 1):
                    avatar_large = q1[0]
                    avatar_large.content = db.Blob(avatar_73)
                    avatar_large.put()
                else:
                    qc1 = db.GqlQuery("SELECT * FROM Counter WHERE name = :1", 'avatar.max')
                    if (qc1.count() == 1):
                        counter1 = qc1[0]
                        counter1.value = counter1.value + 1
                    else:
                        counter1 = Counter()
                        counter1.name = 'avatar.max'
                        counter1.value = 1
                    counter1.put()
                    avatar_large = Avatar()
                    avatar_large.name = 'node_' + str(node.num) + '_large'
                    avatar_large.content = db.Blob(avatar_73)
                    avatar_large.num = counter1.value
                    avatar_large.put()
                node.avatar_large_url = '/navatar/' + str(node.num) + '/large?r=' + timestamp
                node.put()
                # Normal 48x48
                q2 = db.GqlQuery("SELECT * FROM Avatar WHERE name = :1", 'node_' + str(node.num) + '_normal')
                if (q2.count() == 1):
                    avatar_normal = q2[0]
                    avatar_normal.content = db.Blob(avatar_48)
                    avatar_normal.put()
                else:
                    qc2 = db.GqlQuery("SELECT * FROM Counter WHERE name = :1", 'avatar.max')
                    if (qc2.count() == 1):
                        counter2 = qc2[0]
                        counter2.value = counter2.value + 1
                    else:
                        counter2 = Counter()
                        counter2.name = 'avatar.max'
                        counter2.value = 1
                    counter2.put()
                    avatar_normal = Avatar()
                    avatar_normal.name = 'node_' + str(node.num) + '_normal'
                    avatar_normal.content = db.Blob(avatar_48)
                    avatar_normal.num = counter2.value
                    avatar_normal.put()
                node.avatar_normal_url = '/navatar/' + str(node.num) + '/normal?r=' + timestamp
                node.put() 
                # Mini 24x24
                q3 = db.GqlQuery("SELECT * FROM Avatar WHERE name = :1", 'node_' + str(node.num) + '_mini')
                if (q3.count() == 1):
                    avatar_mini = q3[0]
                    avatar_mini.content = db.Blob(avatar_24)
                    avatar_mini.put()
                else:
                    qc3 = db.GqlQuery("SELECT * FROM Counter WHERE name = :1", 'avatar.max')
                    if (qc3.count() == 1):
                        counter3 = qc3[0]
                        counter3.value = counter3.value + 1
                    else:
                        counter3 = Counter()
                        counter3.name = 'avatar.max'
                        counter3.value = 1
                    counter3.put()
                    avatar_mini = Avatar()
                    avatar_mini.name = 'node_' + str(node.num) + '_mini'
                    avatar_mini.content = db.Blob(avatar_24)
                    avatar_mini.num = counter3.value
                    avatar_mini.put()
                node.avatar_mini_url = '/navatar/' + str(node.num) + '/mini?r=' + timestamp
                node.put()
                # Upload to MobileMe
                use_this = False
                if config.mobileme_enabled and use_this:
                    headers = {'Authorization' : 'Basic ' + base64.b64encode(config.mobileme_username + ':' + config.mobileme_password)}
                    host = 'idisk.me.com'
                    # Sharding
                    timestamp = str(int(time.time()))
                    shard = node.num % 31
                    root = '/' + config.mobileme_username + '/Web/Sites/v2ex/navatars/' + str(shard)
                    root_mini = root + '/mini'
                    root_normal = root + '/normal'
                    root_large = root + '/large'
                    h = httplib.HTTPConnection(host)
                    # Mini
                    h.request('PUT', root_mini + '/' + str(node.num) + '.png', str(avatar_24), headers)
                    response = h.getresponse()
                    if response.status == 201 or response.status == 204:
                        node.avatar_mini_url = 'http://web.me.com/' + config.mobileme_username + '/v2ex/navatars/' + str(shard) + '/mini/' + str(node.num) + '.png?r=' + timestamp
                    # Normal
                    h.request('PUT', root_normal + '/' + str(node.num) + '.png', str(avatar_48), headers)
                    response = h.getresponse()
                    if response.status == 201 or response.status == 204:
                        node.avatar_normal_url = 'http://web.me.com/' + config.mobileme_username + '/v2ex/navatars/' + str(shard) + '/normal/' + str(node.num) + '.png?r=' + timestamp
                    # Large
                    h.request('PUT', root_large + '/' + str(node.num) + '.png', str(avatar_73), headers)
                    response = h.getresponse()
                    if response.status == 201 or response.status == 204:
                        node.avatar_large_url = 'http://web.me.com/' + config.mobileme_username + '/v2ex/navatars/' + str(shard) + '/large/' + str(node.num) + '.png?r=' + timestamp
                    node.put()
                memcache.set('Node_' + str(node.num), node, 86400 * 14)
                memcache.set('Node::' + node.name, node, 86400 * 14)
                memcache.delete('Avatar::node_' + str(node.num) + '_large')
                memcache.delete('Avatar::node_' + str(node.num) + '_normal')
                memcache.delete('Avatar::node_' + str(node.num) + '_mini')
                #self.session['message'] = '新节点头像设置成功'
                self.redirect(dest)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
        

class BackstageRemoveReplyHandler(webapp.RequestHandler):
    def get(self, reply_key):
        member = CheckAuth(self)
        t = self.request.get('t')
        if (member):
            if (member.level == 0) and (str(member.created_ts) == str(t)):
                reply = db.get(db.Key(reply_key))
                if reply:
                    topic = reply.topic
                    reply.delete()
                    q = db.GqlQuery("SELECT __key__ FROM Reply WHERE topic = :1", topic)
                    topic.replies = q.count()
                    if (topic.replies == 0):
                        topic.last_reply_by = None
                    topic.put()
                    pages = 1
                    memcache.delete('Topic_' + str(topic.num))
                    memcache.delete('topic_' + str(topic.num) + '_replies_desc_compressed')
                    memcache.delete('topic_' + str(topic.num) + '_replies_asc_compressed')
                    memcache.delete('topic_' + str(topic.num) + '_replies_filtered_compressed')
                    memcache.delete('topic_' + str(topic.num) + '_replies_desc_rendered_desktop_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_asc_rendered_desktop_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_filtered_rendered_desktop_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_desc_rendered_ios_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_asc_rendered_ios_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_filtered_rendered_ios_' + str(pages))
                    self.redirect('/t/' + str(topic.num))
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageTidyReplyHandler(webapp.RequestHandler):
    def get(self, reply_num):
        member = CheckAuth(self)
        if (member):
            if (member.level == 0):
                q = db.GqlQuery("SELECT * FROM Reply WHERE num = :1", int(reply_num))
                if (q.count() == 1):
                    reply = q[0]
                    topic_num = reply.topic_num
                    q2 = db.GqlQuery("SELECT * FROM Member WHERE username_lower = :1", reply.created_by.lower())
                    member = q2[0]
                    reply.member = member
                    reply.member_num = member.num
                    q3 = db.GqlQuery("SELECT * FROM Topic WHERE num = :1", topic_num)
                    topic = q3[0]
                    # Begin to do real stuff
                    reply2 = Reply(parent=topic)
                    reply2.num = reply.num
                    reply2.content = reply.content
                    reply2.topic = topic
                    reply2.topic_num = topic.num
                    reply2.member = reply.member
                    reply2.member_num = reply.member_num
                    reply2.created_by = reply.created_by
                    reply2.source = reply.source
                    reply2.created = reply.created
                    reply2.last_modified = reply.last_modified
                    reply2.put()
                    reply.delete()
                    self.redirect('/t/' + str(topic_num))
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
            
class BackstageTidyTopicHandler(webapp.RequestHandler):
    def get(self, topic_num):
        member = CheckAuth(self)
        if (member):
            if (member.level == 0):
                q = db.GqlQuery("SELECT * FROM Topic WHERE num = :1", int(topic_num))
                if (q.count() == 1):
                    topic = q[0]
                    q2 = db.GqlQuery("SELECT * FROM Member WHERE num = :1", topic.member_num)
                    member = q2[0]
                    topic.member = member
                    q3 = db.GqlQuery("SELECT * FROM Node WHERE num = :1", topic.node_num)
                    node = q3[0]
                    topic.node = node
                    topic.put()
                    memcache.delete('Topic_' + str(topic.num))
                    self.redirect('/t/' + str(topic.num))
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageDeactivateUserHandler(webapp.RequestHandler):
    def get(self, key):
        member = CheckAuth(self)
        t = self.request.get('t')
        if member:
            if (member.level == 0) and (str(member.created_ts) == str(t)):
                one = db.get(db.Key(key))
                if one:
                    if one.num != 1:
                        memcache.delete(one.auth)
                        one.deactivated = int(time.time())
                        one.password = hashlib.sha1(str(time.time())).hexdigest()
                        one.auth = hashlib.sha1(str(one.num) + ':' + one.password).hexdigest()
                        one.newbie = 1
                        one.noob = 1
                        one.put()
                        memcache.delete('Member_' + str(one.num))
                        return self.redirect('/member/' + one.username)
        return self.redirect('/')               

class BackstageMoveTopicHandler(webapp.RequestHandler):
    def get(self, key):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        topic = db.get(db.Key(key))
        can_move = False
        ttl = 0
        if member:
            if member.level == 0:
                can_move = True
            if topic:
                if topic.member_num == member.num:
                    now = datetime.datetime.now()
                    ttl = 300 - int((now - topic.created).seconds)
                    if ttl > 0:
                        can_move = True
                        template_values['ttl'] = ttl
        template_values['can_move'] = can_move
        if member:
            template_values['member'] = member
            if can_move:
                template_values['page_title'] = site.title + u' › 移动主题'
                template_values['site'] = site
                if topic is not None:
                    node = topic.node
                    template_values['topic'] = topic
                    template_values['node'] = node
                    template_values['system_version'] = SYSTEM_VERSION
                    themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                    template_values['themes'] = themes
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_move_topic.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self, key):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        topic = db.get(db.Key(key))
        can_move = False
        ttl = 0
        if member:
            if member.level == 0:
                can_move = True
            if topic:
                if topic.member_num == member.num:
                    now = datetime.datetime.now()
                    ttl = 300 - int((now - topic.created).seconds)
                    if ttl > 0:
                        can_move = True
                        template_values['ttl'] = ttl
        template_values['can_move'] = can_move
        if member:
            template_values['member'] = member
            if can_move:
                template_values['page_title'] = site.title + u' › 移动主题'
                template_values['site'] = site
                if topic is not None:
                    errors = 0
                    node = topic.node
                    template_values['topic'] = topic
                    template_values['node'] = node
                    template_values['system_version'] = SYSTEM_VERSION
                    destination = self.request.get('destination')
                    if destination is not None:
                        node_new = GetKindByName('Node', destination)
                        if node_new is not False:
                            node_new = db.get(node_new.key())
                            node_old = topic.node
                            node_old.topics = node_old.topics - 1
                            node_old.put()
                            node_new.topics = node_new.topics + 1
                            node_new.put()
                            topic.node = node_new
                            topic.node_num = node_new.num
                            topic.node_name = node_new.name
                            topic.node_title = node_new.title
                            topic.put()
                            memcache.delete('Topic_' + str(topic.num))
                            memcache.delete('Node_' + str(node_old.num))
                            memcache.delete('Node_' + str(node_new.num))
                            memcache.delete('Node::' + str(node_old.name))
                            memcache.delete('Node::' + str(node_new.name))
                            memcache.delete('q_latest_16')
                            memcache.delete('home_rendered')
                            memcache.delete('home_rendered_mobile')
                            self.redirect('/t/' + str(topic.num))
                        else:
                            errors = errors + 1
                    else:
                        errors = errors + 1
                    if errors > 0:
                        themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                        template_values['themes'] = themes
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_move_topic.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
        
class BackstageSiteHandler(webapp.RequestHandler):
    def get(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › 站点设置'
                template_values['site'] = site
                template_values['site_title'] = site.title
                template_values['site_slogan'] = site.slogan
                template_values['site_domain'] = site.domain
                template_values['site_description'] = site.description
                if site.home_categories is not None:
                    template_values['site_home_categories'] = site.home_categories
                else:
                    template_values['site_home_categories'] = ''
                if site.analytics is not None:
                    template_values['site_analytics'] = site.analytics
                else:
                    template_values['site_analytics'] = ''
                if site.topic_view_level is not None:
                    template_values['site_topic_view_level'] = site.topic_view_level
                else:
                    template_values['site_topic_view_level'] = -1
                if site.topic_create_level is not None:
                    template_values['site_topic_create_level'] = site.topic_create_level
                else:
                    template_values['site_topic_create_level'] = 1000
                if site.topic_reply_level is not None:
                    template_values['site_topic_reply_level'] = site.topic_reply_level
                else:
                    template_values['site_topic_reply_level'] = 1000
                if site.meta is not None:
                    template_values['site_meta'] = site.meta
                else:
                    template_values['site_meta'] = ''
                if site.home_top is not None:
                    template_values['site_home_top'] = site.home_top
                else:
                    template_values['site_home_top'] = ''
                if site.theme is not None:
                    template_values['site_theme'] = site.theme
                else:
                    template_values['site_theme'] = 'default'
                if site.data_migration_mode is not None:
                    template_values['site_data_migration_mode'] = site.data_migration_mode
                else:
                    template_values['site_data_migration_mode'] = 0
                s = GetLanguageSelect(site.l10n)
                template_values['s'] = s
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                template_values['themes'] = themes
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_site.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
        else:
            self.redirect('/')
    
    def post(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › 站点设置'
                template_values['site'] = site
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                errors = 0
                # Verification: title (required)
                site_title_error = 0
                site_title_error_messages = ['',
                    u'请输入站点名',
                    u'站点名长度不能超过 40 个字符'
                ]
                site_title = self.request.get('title').strip()
                if (len(site_title) == 0):
                    errors = errors + 1
                    site_title_error = 1    
                else:
                    if (len(site_title) > 40):
                        errors = errors + 1
                        site_title_error = 1
                template_values['site_title'] = site_title
                template_values['site_title_error'] = site_title_error
                template_values['site_title_error_message'] = site_title_error_messages[site_title_error]
                # Verification: slogan (required)
                site_slogan_error = 0
                site_slogan_error_messages = ['',
                    u'请输入站点标语',
                    u'站点标语长度不能超过 140 个字符'
                ]
                site_slogan = self.request.get('slogan').strip()
                if (len(site_slogan) == 0):
                    errors = errors + 1
                    site_slogan_error = 1    
                else:
                    if (len(site_slogan) > 140):
                        errors = errors + 1
                        site_slogan_error = 1
                template_values['site_slogan'] = site_slogan
                template_values['site_slogan_error'] = site_slogan_error
                template_values['site_slogan_error_message'] = site_slogan_error_messages[site_slogan_error]
                # Verification: domain (required)
                site_domain_error = 0
                site_domain_error_messages = ['',
                    u'请输入主要域名',
                    u'主要域名长度不能超过 40 个字符'
                ]
                site_domain = self.request.get('domain').strip()
                if (len(site_domain) == 0):
                    errors = errors + 1
                    site_domain_error = 1    
                else:
                    if (len(site_domain) > 40):
                        errors = errors + 1
                        site_domain_error = 1
                template_values['site_domain'] = site_domain
                template_values['site_domain_error'] = site_domain_error
                template_values['site_domain_error_message'] = site_domain_error_messages[site_domain_error]
                # Verification: description (required)
                site_description_error = 0
                site_description_error_messages = ['',
                    u'请输入站点简介',
                    u'站点简介长度不能超过 200 个字符'
                ]
                site_description = self.request.get('description').strip()
                if (len(site_description) == 0):
                    errors = errors + 1
                    site_description_error = 1    
                else:
                    if (len(site_description) > 200):
                        errors = errors + 1
                        site_description_error = 1
                template_values['site_description'] = site_description
                template_values['site_description_error'] = site_description_error
                template_values['site_description_error_message'] = site_description_error_messages[site_description_error]
                # Verification: analytics (optional)
                site_analytics_error = 0
                site_analytics_error_messages = ['',
                    u'Analytics ID 格式不正确'
                ]
                site_analytics = self.request.get('analytics').strip()
                if len(site_analytics) > 0:
                    if re.findall('^UA\-[0-9]+\-[0-9]+$', site_analytics):
                        site_analytics_error = 0
                    else:
                        errors = errors + 1
                        site_analytics_error = 1
                else:
                    site_analytics = ''
                template_values['site_analytics'] = site_analytics
                template_values['site_analytics_error'] = site_analytics_error
                template_values['site_analytics_error_message'] = site_analytics_error_messages[site_analytics_error]
                # Verification: l10n (required)
                site_l10n = self.request.get('l10n').strip()
                supported = GetSupportedLanguages()
                if site_l10n == '':
                    site_l10n = site.l10n
                else:
                    if site_l10n not in supported:
                        site_l10n = site.l10n
                s = GetLanguageSelect(site_l10n)
                template_values['s'] = s
                template_values['site_l10n'] = site_l10n
                # Verification: home_categories (optional)
                site_home_categories_error = 0
                site_home_categories_error_messages = ['',
                    u'首页分类信息不要超过 2000 个字符'
                ]
                site_home_categories = self.request.get('home_categories').strip()
                site_home_categories_length = len(site_home_categories)
                if len(site_home_categories) > 0:
                    if site_home_categories_length > 2000:
                        errors = errors + 1
                        site_home_categories_error = 1
                else:
                    site_home_categories = ''
                template_values['site_home_categories'] = site_home_categories
                template_values['site_home_categories_error'] = site_home_categories_error
                template_values['site_home_categories_error_message'] = site_home_categories_error_messages[site_home_categories_error]
                # Verification: topic_view_level (default=-1)
                site_topic_view_level = self.request.get('topic_view_level')
                try:
                    site_topic_view_level = int(site_topic_view_level)
                    if site_topic_view_level < -1:
                        site_topic_view_level = -1
                except:
                    site_topic_view_level = -1
                template_values['site_topic_view_level'] = site_topic_view_level
                # Verification: topic_create_level (default=1000)
                site_topic_create_level = self.request.get('topic_create_level')
                try:
                    site_topic_create_level = int(site_topic_create_level)
                    if site_topic_create_level < -1:
                        site_topic_create_level = 1000
                except:
                    site_topic_create_level = 1000
                template_values['site_topic_create_level'] = site_topic_create_level
                # Verification: topic_reply_level (default=1000)
                site_topic_reply_level = self.request.get('topic_reply_level')
                try:
                    site_topic_reply_level = int(site_topic_reply_level)
                    if site_topic_reply_level < -1:
                        site_topic_reply_level = 1000
                except:
                    site_topic_reply_level = 1000
                template_values['site_topic_reply_level'] = site_topic_reply_level
                # Verification: meta
                site_meta = self.request.get('meta')
                template_values['site_meta'] = site_meta
                # Verification: home_top
                site_home_top = self.request.get('home_top')
                template_values['site_home_top'] = site_home_top
                # Verification: theme
                site_theme = self.request.get('theme')
                themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                template_values['themes'] = themes
                if site_theme in themes:
                    template_values['site_theme'] = site_theme
                else:
                    site_theme = 'default'
                    template_values['site_theme'] = site_theme
                # Verification: data_migration_mode
                site_data_migration_mode = self.request.get('data_migration_mode')
                if site_data_migration_mode == 'on':
                    template_values['site_data_migration_mode'] = 1
                else:
                    template_values['site_data_migration_mode'] = 0
                
                template_values['errors'] = errors
                
                if errors == 0:
                    site.title = site_title
                    site.slogan = site_slogan
                    site.domain = site_domain
                    site.description = site_description
                    if site_home_categories != '':
                        site.home_categories = site_home_categories
                    if site_analytics != '':
                        site.analytics = site_analytics
                    site.l10n = site_l10n
                    site.topic_view_level = site_topic_view_level
                    site.topic_create_level = site_topic_create_level
                    site.topic_reply_level = site_topic_reply_level
                    site.meta = site_meta
                    site.home_top = site_home_top
                    site.theme = site_theme
                    site.data_migration_mode = template_values['site_data_migration_mode']
                    site.put()
                    memcache.delete('index_categories')
                    template_values['message'] = l10n.site_settings_updated;
                    template_values['site'] = site
                    memcache.delete('site')
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_site.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
        else:
            self.redirect('/')

class BackstageTopicHandler(webapp.RequestHandler):
    def get(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + l10n.topic_settings.decode('utf-8')
                template_values['site'] = site
                template_values['site_use_topic_types'] = site.use_topic_types
                if site.topic_types is None:
                    template_values['site_topic_types'] = ''
                else:
                    template_values['site_topic_types'] = site.topic_types
                if site.use_topic_types is not True:
                    s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                else:
                    s = '<select name="use_topic_types"><option value="1" selected="selected">Enabled</option><option value="0">Disabled</option></select>'
                template_values['s'] = s
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_topic.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
        else:
            self.redirect('/')

    def post(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + l10n.topic_settings.decode('utf-8')
                template_values['site'] = site
                template_values['site_use_topic_types'] = site.use_topic_types
                if site.topic_types is None:
                    template_values['site_topic_types'] = ''
                else:
                    template_values['site_topic_types'] = site.topic_types
                if site.use_topic_types is not True:
                    s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                else:
                    s = '<select name="use_topic_types"><option value="1" selected="selected">Enabled</option><option value="0">Disabled</option></select>'
                template_values['s'] = s
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                errors = 0
                # Verification: use_topic_types
                site_use_topic_types = self.request.get('use_topic_types').strip()
                if site_use_topic_types is None:
                    s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                else:
                    if site_use_topic_types == '1':
                        s = '<select name="use_topic_types"><option value="1" selected="selected">Enabled</option><option value="0">Disabled</option></select>'
                    else:
                        s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                template_values['s'] = s
                # Verification: topic_types
                site_topic_types = self.request.get('topic_types').strip()
                if errors == 0:
                    if site_use_topic_types == '1':
                        site.use_topic_types = True
                    else:
                        site.use_topic_types = False
                    site.topic_types = site_topic_types
                    site.put()
                    memcache.delete('site')
                    self.redirect('/backstage')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_topic.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
        else:
            self.redirect('/')


class BackstageRemoveMemcacheHandler(webapp.RequestHandler):
    def post(self):
        member = CheckAuth(self)
        if member:
            if member.level == 0:
                mc = self.request.get('mc')
                if mc is not None:
                    memcache.delete(mc)
        self.redirect('/backstage')


class BackstageMemberHandler(webapp.RequestHandler):
    def get(self, member_username):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                member_username_lower = member_username.lower()
                q = db.GqlQuery("SELECT * FROM Member WHERE username_lower = :1", member_username_lower)
                if (q.count() == 1):
                    one = q[0]
                    template_values['one'] = one
                    errors = 0
                    template_values['one_username'] = one.username
                    template_values['one_email'] = one.email
                    if one.avatar_large_url is None:
                        template_values['one_avatar_large_url'] = ''
                    else:
                        template_values['one_avatar_large_url'] = one.avatar_large_url
                    if one.avatar_normal_url is None:
                        template_values['one_avatar_normal_url'] = ''
                    else:
                        template_values['one_avatar_normal_url'] = one.avatar_normal_url
                    if one.avatar_mini_url is None:
                        template_values['one_avatar_mini_url'] = ''
                    else:
                        template_values['one_avatar_mini_url'] = one.avatar_mini_url
                    if one.bio is None:
                        template_values['one_bio'] = ''
                    else:
                        template_values['one_bio'] = one.bio
                    template_values['one_level'] = one.level
                    template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + one.username
                    template_values['site'] = site
                    template_values['member'] = member
                    template_values['system_version'] = SYSTEM_VERSION
                    template_values['latest_members'] = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT 5")
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_member.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
                
        else:
            self.redirect('/')
            

    def post(self, member_username):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                member_username_lower = member_username.lower()
                q = db.GqlQuery("SELECT * FROM Member WHERE username_lower = :1", member_username_lower)
                if (q.count() == 1):
                    one = q[0]
                    template_values['one'] = one
                    errors = 0
                    # Verification: username
                    one_username_error = 0
                    one_username_error_messages = ['',
                        l10n.username_empty,
                        l10n.username_too_long,
                        l10n.username_too_short,
                        l10n.username_invalid,
                        l10n.username_taken]
                    one_username = self.request.get('username').strip()
                    if (len(one_username) == 0):
                        errors = errors + 1
                        one_username_error = 1
                    else:
                        if (len(one_username) > 32):
                            errors = errors + 1
                            one_username_error = 2
                        else:
                            if (len(one_username) < 3):
                                errors = errors + 1
                                one_username_error = 3
                            else:
                                if (re.search('^[a-zA-Z0-9\_]+$', one_username)):
                                    q = db.GqlQuery('SELECT * FROM Member WHERE username_lower = :1 AND num != :2', one_username.lower(), one.num)
                                    if (q.count() > 0):
                                        errors = errors + 1
                                        one_username_error = 5
                                else:
                                    errors = errors + 1
                                    one_username_error = 4
                    template_values['one_username'] = one_username
                    template_values['one_username_error'] = one_username_error
                    template_values['one_username_error_message'] = one_username_error_messages[one_username_error]
                    # Verification: email
                    one_email_error = 0
                    one_email_error_messages = ['',
                        u'请输入电子邮件地址',
                        u'电子邮件地址长度不能超过 32 个字符',
                        u'输入的电子邮件地址不符合规则',
                        u'这个电子邮件地址已经有人注册过了']
                    one_email = self.request.get('email').strip()
                    if (len(one_email) == 0):
                        errors = errors + 1
                        one_email_error = 1
                    else:
                        if (len(one_email) > 32):
                            errors = errors + 1
                            one_email_error = 2
                        else:
                            p = re.compile(r"(?:^|\s)[-a-z0-9_.]+@(?:[-a-z0-9]+\.)+[a-z]{2,6}(?:\s|$)", re.IGNORECASE)
                            if (p.search(one_email)):
                                q = db.GqlQuery('SELECT * FROM Member WHERE email = :1 AND num != :2', one_email.lower(), one.num)
                                if (q.count() > 0):
                                    errors = errors + 1
                                    one_email_error = 4
                            else:
                                errors = errors + 1
                                one_email_error = 3
                    template_values['one_email'] = one_email.lower()
                    template_values['one_email_error'] = one_email_error
                    template_values['one_email_error_message'] = one_email_error_messages[one_email_error]
                    # Verification: avatar
                    one_avatar_large_url = self.request.get('avatar_large_url')
                    template_values['one_avatar_large_url'] = one_avatar_large_url
                    one_avatar_normal_url = self.request.get('avatar_normal_url')
                    template_values['one_avatar_normal_url'] = one_avatar_normal_url
                    one_avatar_mini_url = self.request.get('avatar_mini_url')
                    template_values['one_avatar_mini_url'] = one_avatar_mini_url
                    # Verification: bio
                    one_bio = self.request.get('bio')
                    template_values['one_bio'] = one_bio
                    # Verification: level
                    one_level = self.request.get('level')
                    try:
                        one_level = int(one_level)
                    except:
                        if one.num == 1:
                            one_level = 0
                        else:
                            one_level = 1000
                    template_values['one_level'] = one_level
                    if errors == 0:
                        one.username = one_username
                        one.username_lower = one_username.lower()
                        one.email = one_email
                        one.avatar_large_url = one_avatar_large_url
                        one.avatar_normal_url = one_avatar_normal_url
                        one.avatar_mini_url = one_avatar_mini_url
                        one.bio = one_bio
                        one.level = one_level
                        one.put()
                        memcache.delete('Member_' + str(one.num))
                        memcache.delete('Member::' + one_username.lower())
                        self.redirect('/backstage')
                    else:
                        template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + one.username
                        template_values['site'] = site
                        template_values['member'] = member
                        template_values['system_version'] = SYSTEM_VERSION
                        template_values['latest_members'] = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT 5")
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_member.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/backstage')

        else:
            self.redirect('/')

class BackstageMembersHandler(webapp.RequestHandler):
    def get(self):
        template_values = {}
        site = GetSite()
        template_values['site'] = site
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['member'] = member
                template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › 浏览所有会员'
                member_total = memcache.get('member_total')
                if member_total is None:
                    q3 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'member.total'")
                    if (q3.count() > 0):
                        member_total = q3[0].value
                    else:
                        member_total = 0
                    memcache.set('member_total', member_total, 600)
                template_values['member_total'] = member_total
                page_size = 60
                pages = 1
                if member_total > page_size:
                    if (member_total % page_size) > 0:
                        pages = int(math.floor(member_total / page_size)) + 1
                    else:
                        pages = int(math.floor(member_total / page_size))
                try:
                    page_current = int(self.request.get('p'))
                    if page_current < 1:
                        page_current = 1
                    if page_current > pages:
                        page_current = pages
                except:
                    page_current = 1
                page_start = (page_current - 1) * page_size
                template_values['pages'] = pages
                template_values['page_current'] = page_current
                i = 1
                ps = []
                while i <= pages:
                    ps.append(i)
                    i = i + 1
                template_values['ps'] = ps
                q = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT " + str(page_start )+ "," + str(page_size))
                template_values['members'] = q
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_members.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageRemoveNotificationHandler(BaseHandler):
    def get(self, key):
        o = db.get(db.Key(key))
        if o and self.member:
            if type(o).__name__ == 'Notification':
                if o.for_member_num == self.member.num:
                    o.delete()
                    memcache.delete('nn::' + self.member.username_lower)
        self.redirect('/notifications')

def main():
    application = webapp.WSGIApplication([
    ('/backstage', BackstageHomeHandler),
    ('/backstage/new/minisite', BackstageNewMinisiteHandler),
    ('/backstage/minisite/(.*)', BackstageMinisiteHandler),
    ('/backstage/remove/minisite/(.*)', BackstageRemoveMinisiteHandler),
    ('/backstage/new/page/(.*)', BackstageNewPageHandler),
    ('/backstage/page/(.*)', BackstagePageHandler),
    ('/backstage/remove/page/(.*)', BackstageRemovePageHandler),
    ('/backstage/new/section', BackstageNewSectionHandler),
    ('/backstage/section/(.*)', BackstageSectionHandler),
    ('/backstage/new/node/(.*)', BackstageNewNodeHandler),
    ('/backstage/node/([a-z0-9A-Z]+)', BackstageNodeHandler),
    ('/backstage/node/([a-z0-9A-Z]+)/avatar', BackstageNodeAvatarHandler),
    ('/backstage/remove/reply/(.*)', BackstageRemoveReplyHandler),
    ('/backstage/tidy/reply/([0-9]+)', BackstageTidyReplyHandler),
    ('/backstage/tidy/topic/([0-9]+)', BackstageTidyTopicHandler),
    ('/backstage/deactivate/user/(.*)', BackstageDeactivateUserHandler),
    ('/backstage/move/topic/(.*)', BackstageMoveTopicHandler),
    ('/backstage/site', BackstageSiteHandler),
    ('/backstage/topic', BackstageTopicHandler),
    ('/backstage/remove/mc', BackstageRemoveMemcacheHandler),
    ('/backstage/member/(.*)', BackstageMemberHandler),
    ('/backstage/members', BackstageMembersHandler),
    ('/backstage/remove/notification/(.*)', BackstageRemoveNotificationHandler),
    ],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()
#!/usr/bin/env python
# coding=utf-8

import base64
import os
import re
import time
import datetime
import hashlib
import logging
import string
import StringIO
import random
import math

from google.appengine.ext import webapp
from google.appengine.api import memcache
from google.appengine.api import images
from google.appengine.ext import db
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template

from v2ex.babel import Avatar
from v2ex.babel import Member
from v2ex.babel import Counter
from v2ex.babel import Section
from v2ex.babel import Node
from v2ex.babel import Site
from v2ex.babel import Minisite
from v2ex.babel import Page

from v2ex.babel import SYSTEM_VERSION

from v2ex.babel.security import *
from v2ex.babel.ext.cookies import Cookies
from v2ex.babel.ua import *
from v2ex.babel.da import *
from v2ex.babel.l10n import *

from v2ex.babel.handlers import BaseHandler

template.register_template_library('v2ex.templatetags.filters')

import config

class BackstageHomeHandler(webapp.RequestHandler):
    def get(self):
        site = GetSite()
        browser = detect(self.request)
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values = {}
        template_values['l10n'] = l10n
        template_values['site'] = site
        template_values['rnd'] = random.randrange(1, 100)
        template_values['system_version'] = SYSTEM_VERSION
        template_values['member'] = member
        template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8')
        member_total = memcache.get('member_total')
        if member_total is None:
            q3 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'member.total'")
            if (q3.count() > 0):
                member_total = q3[0].value
            else:
                member_total = 0
            memcache.set('member_total', member_total, 600)
        template_values['member_total'] = member_total
        topic_total = memcache.get('topic_total')
        if topic_total is None:
            q4 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'topic.total'")
            if (q4.count() > 0):
                topic_total = q4[0].value
            else:
                topic_total = 0
            memcache.set('topic_total', topic_total, 600)
        template_values['topic_total'] = topic_total
        reply_total = memcache.get('reply_total')
        if reply_total is None:
            q5 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'reply.total'")
            if (q5.count() > 0):
                reply_total = q5[0].value
            else:
                reply_total = 0
            memcache.set('reply_total', reply_total, 600)
        template_values['reply_total'] = reply_total
        if (member):
            if (member.level == 0):
                q = db.GqlQuery("SELECT * FROM Section ORDER BY nodes DESC")
                template_values['sections'] = q
                q2 = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT 5")
                template_values['latest_members'] = q2
                q3 = db.GqlQuery("SELECT * FROM Minisite ORDER BY created DESC")
                template_values['minisites'] = q3
                q4 = db.GqlQuery("SELECT * FROM Node ORDER BY last_modified DESC LIMIT 8")
                template_values['latest_nodes'] = q4
                if browser['ios']:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_home.html')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_home.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
            
class BackstageNewMinisiteHandler(webapp.RequestHandler):
    def get(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['page_title'] = site.title + u' › 添加新站点'
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):    
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_minisite.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['page_title'] = site.title + u' › 添加新站点'
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                errors = 0
                # Verification: name
                minisite_name_error = 0
                minisite_name_error_messages = ['',
                    u'请输入站点名',
                    u'站点名长度不能超过 32 个字符',
                    u'站点名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个站点名已经存在了']
                minisite_name = self.request.get('name').strip().lower()
                if (len(minisite_name) == 0):
                    errors = errors + 1
                    minisite_name_error = 1
                else:
                    if (len(minisite_name) > 32):
                        errors = errors + 1
                        minisite_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', minisite_name)):
                            q = db.GqlQuery('SELECT __key__ FROM Minisite WHERE name = :1', minisite_name.lower())
                            if (q.count() > 0):
                                errors = errors + 1
                                minisite_name_error = 4
                        else:
                            errors = errors + 1
                            minisite_name_error = 3
                template_values['minisite_name'] = minisite_name
                template_values['minisite_name_error'] = minisite_name_error
                template_values['minisite_name_error_message'] = minisite_name_error_messages[minisite_name_error]
                # Verification: title
                minisite_title_error = 0
                minisite_title_error_messages = ['',
                    u'请输入站点标题',
                    u'站点标题长度不能超过 32 个字符'
                ]
                minisite_title = self.request.get('title').strip()
                if (len(minisite_title) == 0):
                    errors = errors + 1
                    minisite_title_error = 1
                else:
                    if (len(minisite_title) > 32):
                        errors = errors + 1
                        minisite_title_error = 2
                template_values['minisite_title'] = minisite_title
                template_values['minisite_title_error'] = minisite_title_error
                template_values['minisite_title_error_message'] = minisite_title_error_messages[minisite_title_error]
                # Verification: description
                minisite_description_error = 0
                minisite_description_error_messages = ['',
                    u'请输入站点描述',
                    u'站点描述长度不能超过 2000 个字符'
                ]
                minisite_description = self.request.get('description').strip()
                if (len(minisite_description) == 0):
                    errors = errors + 1
                    minisite_description_error = 1
                else:
                    if (len(minisite_description) > 2000):
                        errors = errors + 1
                        minisite_description_error = 2
                template_values['minisite_description'] = minisite_description
                template_values['minisite_description_error'] = minisite_description_error
                template_values['minisite_description_error_message'] = minisite_description_error_messages[minisite_description_error]
                template_values['errors'] = errors
                if (errors == 0):
                    minisite = Minisite()
                    q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'minisite.max')
                    if (q.count() == 1):
                        counter = q[0]
                        counter.value = counter.value + 1
                    else:
                        counter = Counter()
                        counter.name = 'minisite.max'
                        counter.value = 1
                    minisite.num = counter.value
                    minisite.name = minisite_name
                    minisite.title = minisite_title
                    minisite.description = minisite_description
                    minisite.put()
                    counter.put()
                    self.redirect('/backstage')
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_minisite.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
            
class BackstageMinisiteHandler(webapp.RequestHandler):
    def get(self, minisite_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['page_title'] = site.title + u' › Minisite'
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                minisite = GetKindByName('Minisite', minisite_name)
                if minisite is not False:
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title
                    q = db.GqlQuery("SELECT * FROM Page WHERE minisite = :1 ORDER BY weight ASC", minisite)
                    template_values['pages'] = q
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_minisite.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageNewPageHandler(webapp.RequestHandler):
    def get(self, minisite_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                minisite = GetKindByName('Minisite', minisite_name)
                if minisite is not False:
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › 添加新页面'
                    template_values['page_content_type'] = 'text/html;charset=utf-8'
                    template_values['page_weight'] = 0
                    template_values['page_mode'] = 0
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_page.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

    def post(self, minisite_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                minisite = GetKindByName('Minisite', minisite_name)
                if minisite is False:
                    self.redirect('/backstage')
                else:
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › 添加新页面'
                    errors = 0
                    # Verification: name
                    page_name_error = 0
                    page_name_error_messages = ['',
                        u'请输入页面名',
                        u'页面名长度不能超过 64 个字符',
                        u'页面名只能由 a-Z 0-9 及 . - _ 组成',
                        u'抱歉这个页面名已经存在了']
                    page_name = self.request.get('name').strip().lower()
                    if (len(page_name) == 0):
                        errors = errors + 1
                        page_name_error = 1
                    else:
                        if (len(page_name) > 64):
                            errors = errors + 1
                            page_name_error = 2
                        else:
                            if (re.search('^[a-zA-Z0-9\-\_\.]+$', page_name)):
                                q = db.GqlQuery('SELECT * FROM Page WHERE name = :1', page_name.lower())
                                if (q.count() > 0):
                                    if q[0].minisite.name == minisite.name:
                                        errors = errors + 1
                                        page_name_error = 4
                            else:
                                errors = errors + 1
                                page_name_error = 3
                    template_values['page_name'] = page_name
                    template_values['page_name_error'] = page_name_error
                    template_values['page_name_error_message'] = page_name_error_messages[page_name_error]
                    # Verification: title
                    page_t_error = 0
                    page_t_error_messages = ['',
                        u'请输入页面标题',
                        u'页面标题长度不能超过 100 个字符'
                    ]
                    page_t = self.request.get('t').strip()
                    if (len(page_t) == 0):
                        errors = errors + 1
                        page_t_error = 1
                    else:
                        if (len(page_t) > 100):
                            errors = errors + 1
                            page_t_error = 2
                    template_values['page_t'] = page_t
                    template_values['page_t_error'] = page_t_error
                    template_values['page_t_error_message'] = page_t_error_messages[page_t_error]
                    # Verification: content
                    page_content_error = 0
                    page_content_error_messages = ['',
                        u'请输入页面内容',
                        u'页面内容长度不能超过 200000 个字符'
                    ]
                    page_content = self.request.get('content').strip()
                    if (len(page_content) == 0):
                        errors = errors + 1
                        page_content_error = 1
                    else:
                        if (len(page_content) > 200000):
                            errors = errors + 1
                            page_content_error = 2
                    template_values['page_content'] = page_content
                    template_values['page_content_error'] = page_content_error
                    template_values['page_content_error_message'] = page_content_error_messages[page_content_error]
                    # Verification: mode
                    page_mode = 0
                    page_mode = self.request.get('mode').strip()
                    if page_mode == '1':
                        page_mode = 1
                    else:
                        page_mode = 0
                    # Verification: content_type
                    page_content_type = self.request.get('content_type').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 'text/html;charset=utf-8'
                    else:
                        if (len(page_content_type) > 40):
                            page_content_type = 'text/html;charset=utf-8'
                    template_values['page_content_type'] = page_content_type
                    # Verification: weight
                    page_weight = self.request.get('weight').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 0
                    else:
                        if (len(page_weight) > 9):
                            page_weight = 0
                        else:
                            try:
                                page_weight = int(page_weight)
                            except:
                                page_weight = 0
                    template_values['page_weight'] = page_weight
                    template_values['errors'] = errors
                    if (errors == 0):
                        page = Page(parent=minisite)
                        q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'page.max')
                        if (q.count() == 1):
                            counter = q[0]
                            counter.value = counter.value + 1
                        else:
                            counter = Counter()
                            counter.name = 'page.max'
                            counter.value = 1
                        q2 = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'page.total')
                        if (q2.count() == 1):
                            counter2 = q[0]
                            counter2.value = counter.value + 1
                        else:
                            counter2 = Counter()
                            counter2.name = 'page.total'
                            counter2.value = 1
                        page.num = counter.value
                        page.name = page_name
                        page.title = page_t
                        page.content = page_content
                        if page_mode == 1:
                            from django.template import Context, Template
                            t = Template(page_content)
                            c = Context({"site" : site, "minisite" : page.minisite, "page" : page})
                            output = t.render(c)
                            page.content_rendered = output
                        else:
                            page.content_rendered = page_content
                        page.content_type = page_content_type
                        page.weight = page_weight
                        page.mode = page_mode
                        page.minisite = minisite
                        page.put()
                        counter.put()
                        counter2.put()
                        minisite.pages = minisite.pages + 1
                        minisite.put()
                        memcache.delete('Minisite_' + str(minisite.num))
                        memcache.delete('Minisite::' + str(minisite.name))
                        self.redirect('/backstage/minisite/' + minisite.name)
                    else:    
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_new_page.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageRemoveMinisiteHandler(webapp.RequestHandler):
    def get(self, minisite_key):
        member = CheckAuth(self)
        if member:
            if member.level == 0:
                minisite = db.get(db.Key(minisite_key))
                if minisite:
                    # Delete all contents
                    pages = db.GqlQuery("SELECT * FROM Page WHERE minisite = :1", minisite)
                    for page in pages:
                        memcache.delete('Page_' + str(page.num))
                        memcache.delete('Page::' + str(page.name))
                        memcache.delete(minisite.name + '/' + page.name)
                        page.delete()
                    minisite.pages = 0
                    minisite.put()
                    # Delete the minisite
                    memcache.delete('Minisite_' + str(minisite.num))
                    memcache.delete('Minisite::' + str(minisite.name))
                    minisite.delete()
                    self.redirect('/backstage')
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstagePageHandler(webapp.RequestHandler):
    def get(self, page_key):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                page = db.get(db.Key(page_key))
                if page:
                    minisite = page.minisite
                    template_values['page'] = page
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › ' + page.title + u' › 编辑'
                    template_values['page_name'] = page.name
                    template_values['page_t'] = page.title
                    template_values['page_content'] = page.content
                    template_values['page_content_type'] = page.content_type
                    template_values['page_mode'] = page.mode
                    template_values['page_weight'] = page.weight
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_page.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

    def post(self, page_key):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                page = db.get(db.Key(page_key))
                if page:
                    minisite = page.minisite
                    template_values['minisite'] = minisite
                    template_values['page_title'] = site.title + u' › ' + minisite.title + u' › 添加新页面'
                    errors = 0
                    # Verification: name
                    page_name_error = 0
                    page_name_error_messages = ['',
                        u'请输入页面名',
                        u'页面名长度不能超过 64 个字符',
                        u'页面名只能由 a-Z 0-9 及 . - _ 组成',
                        u'抱歉这个页面名已经存在了']
                    page_name = self.request.get('name').strip().lower()
                    if (len(page_name) == 0):
                        errors = errors + 1
                        page_name_error = 1
                    else:
                        if (len(page_name) > 64):
                            errors = errors + 1
                            page_name_error = 2
                        else:
                            if (re.search('^[a-zA-Z0-9\-\_\.]+$', page_name)):
                                q = db.GqlQuery('SELECT * FROM Page WHERE name = :1 AND minisite = :2', page_name.lower(), page.minisite)
                                if (q.count() > 0):
                                    if q[0].num != page.num:
                                        errors = errors + 1
                                        page_name_error = 4
                            else:
                                errors = errors + 1
                                page_name_error = 3
                    template_values['page_name'] = page_name
                    template_values['page_name_error'] = page_name_error
                    template_values['page_name_error_message'] = page_name_error_messages[page_name_error]
                    # Verification: title
                    page_t_error = 0
                    page_t_error_messages = ['',
                        u'请输入页面标题',
                        u'页面标题长度不能超过 100 个字符'
                    ]
                    page_t = self.request.get('t').strip()
                    if (len(page_t) == 0):
                        errors = errors + 1
                        page_t_error = 1
                    else:
                        if (len(page_t) > 100):
                            errors = errors + 1
                            page_t_error = 2
                    template_values['page_t'] = page_t
                    template_values['page_t_error'] = page_t_error
                    template_values['page_t_error_message'] = page_t_error_messages[page_t_error]
                    # Verification: content
                    page_content_error = 0
                    page_content_error_messages = ['',
                        u'请输入页面内容',
                        u'页面内容长度不能超过 200000 个字符'
                    ]
                    page_content = self.request.get('content').strip()
                    if (len(page_content) == 0):
                        errors = errors + 1
                        page_content_error = 1
                    else:
                        if (len(page_content) > 200000):
                            errors = errors + 1
                            page_content_error = 2
                    template_values['page_content'] = page_content
                    template_values['page_content_error'] = page_content_error
                    template_values['page_content_error_message'] = page_content_error_messages[page_content_error]
                    # Verification: mode
                    page_mode = 0
                    page_mode = self.request.get('mode').strip()
                    if page_mode == '1':
                        page_mode = 1
                    else:
                        page_mode = 0
                    # Verification: content_type
                    page_content_type = self.request.get('content_type').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 'text/html;charset=utf-8'
                    else:
                        if (len(page_content_type) > 40):
                            page_content_type = 'text/html;charset=utf-8'
                    template_values['page_content_type'] = page_content_type
                    # Verification: weight
                    page_weight = self.request.get('weight').strip()
                    if (len(page_content_type) == 0):
                        page_content_type = 0
                    else:
                        if (len(page_weight) > 9):
                            page_weight = 0
                        else:
                            try:
                                page_weight = int(page_weight)
                            except:
                                page_weight = 0
                    template_values['page_weight'] = page_weight
                    template_values['errors'] = errors
                    if (errors == 0):
                        page.name = page_name
                        page.title = page_t
                        page.content = page_content
                        if page.mode == 1:
                            from django.template import Context, Template
                            t = Template(page_content)
                            c = Context({"site" : site, "minisite" : page.minisite, "page" : page})
                            output = t.render(c)
                            page.content_rendered = output
                        else:
                            page.content_rendered = page_content
                        page.content_type = page_content_type
                        page.mode = page_mode
                        page.weight = page_weight
                        page.put()
                        memcache.delete('Page_' + str(page.num))
                        memcache.delete('Page::' + str(page.name))
                        memcache.delete(minisite.name + '/' + page.name)
                        self.redirect('/backstage/minisite/' + minisite.name)
                    else:    
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_page.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
class BackstageRemovePageHandler(webapp.RequestHandler):
    def get(self, page_key):
        member = CheckAuth(self)
        if member:
            if member.level == 0:
                page = db.get(db.Key(page_key))
                if page:
                    memcache.delete('Page_' + str(page.num))
                    memcache.delete('Page::' + str(page.name))
                    memcache.delete(page.minisite.name + '/' + page.name)
                    minisite = page.minisite
                    page.delete()
                    minisite.pages = minisite.pages - 1
                    minisite.put()
                    self.redirect('/backstage/minisite/' + minisite.name)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageNewSectionHandler(webapp.RequestHandler):
    def get(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):    
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_section.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        template_values['member'] = member
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                errors = 0
                # Verification: name
                section_name_error = 0
                section_name_error_messages = ['',
                    u'请输入区域名',
                    u'区域名长度不能超过 32 个字符',
                    u'区域名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个区域名已经存在了']
                section_name = self.request.get('name').strip().lower()
                if (len(section_name) == 0):
                    errors = errors + 1
                    section_name_error = 1
                else:
                    if (len(section_name) > 32):
                        errors = errors + 1
                        section_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', section_name)):
                            q = db.GqlQuery('SELECT __key__ FROM Section WHERE name = :1', section_name.lower())
                            if (q.count() > 0):
                                errors = errors + 1
                                section_name_error = 4
                        else:
                            errors = errors + 1
                            section_name_error = 3
                template_values['section_name'] = section_name
                template_values['section_name_error'] = section_name_error
                template_values['section_name_error_message'] = section_name_error_messages[section_name_error]
                # Verification: title
                section_title_error = 0
                section_title_error_messages = ['',
                    u'请输入区域标题',
                    u'区域标题长度不能超过 32 个字符'
                ]
                section_title = self.request.get('title').strip()
                if (len(section_title) == 0):
                    errors = errors + 1
                    section_title_error = 1
                else:
                    if (len(section_title) > 32):
                        errors = errors + 1
                        section_title_error = 2
                template_values['section_title'] = section_title
                template_values['section_title_error'] = section_title_error
                template_values['section_title_error_message'] = section_title_error_messages[section_title_error]
                # Verification: title
                section_title_alternative_error = 0
                section_title_alternative_error_messages = ['',
                    u'请输入区域副标题',
                    u'区域标题长度不能超过 32 个字符'
                ]
                section_title_alternative = self.request.get('title_alternative').strip()
                if (len(section_title_alternative) == 0):
                    errors = errors + 1
                    section_title_alternative_error = 1
                else:
                    if (len(section_title_alternative) > 32):
                        errors = errors + 1
                        section_title_alternative_error = 2
                template_values['section_title_alternative'] = section_title_alternative
                template_values['section_title_alternative_error'] = section_title_alternative_error
                template_values['section_title_alternative_error_message'] = section_title_alternative_error_messages[section_title_alternative_error]
                template_values['errors'] = errors
                if (errors == 0):
                    section = Section()
                    q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'section.max')
                    if (q.count() == 1):
                        counter = q[0]
                        counter.value = counter.value + 1
                    else:
                        counter = Counter()
                        counter.name = 'section.max'
                        counter.value = 1
                    section.num = counter.value
                    section.name = section_name
                    section.title = section_title
                    section.title_alternative = section_title_alternative
                    section.put()
                    counter.put()
                    self.redirect('/backstage')
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_section.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageSectionHandler(webapp.RequestHandler):
    def get(self, section_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['rnd'] = random.randrange(1, 100)
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                template_values['member'] = member
                q = db.GqlQuery("SELECT * FROM Section WHERE name = :1", section_name)
                section = False
                if (q.count() == 1):
                    section = q[0]
                    template_values['section'] = section
                    template_values['page_title'] = site.title + u' › 后台 › ' + section.title
                    template_values['section_name'] = section.name
                    template_values['section_title'] = section.title
                    template_values['section_title_alternative'] = section.title_alternative
                    if section.header:
                        template_values['section_header'] = section.header
                    else:
                        template_values['section_header'] = ''
                    if section.footer:
                        template_values['section_footer'] = section.footer
                    else:
                        template_values['section_footer'] = ''
                else:
                    template_values['section'] = section
                if (section):
                    template_values['section'] = section
                    q2 = db.GqlQuery("SELECT * FROM Node WHERE section_num = :1 ORDER BY last_modified DESC LIMIT 10", section.num)
                    template_values['recent_modified'] = q2
                else:
                    template_values['nodes'] = False
                if browser['ios']:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_section.html')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_section.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self, section_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['rnd'] = random.randrange(1, 100)
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['member'] = member
                section = GetKindByName('Section', section_name)
                if section is not False:
                    template_values['section'] = section
                    errors = 0
                    # Verification: name
                    section_name_error = 0
                    section_name_error_messages = ['',
                        u'请输入区域名',
                        u'区域名长度不能超过 32 个字符',
                        u'区域名只能由 a-Z 0-9 及 - 和 _ 组成',
                        u'抱歉这个区域名已经存在了']
                    section_name = self.request.get('name').strip().lower()
                    if (len(section_name) == 0):
                        errors = errors + 1
                        section_name_error = 1
                    else:
                        if (len(section_name) > 32):
                            errors = errors + 1
                            section_name_error = 2
                        else:
                            if (re.search('^[a-zA-Z0-9\-\_]+$', section_name)):
                                q = db.GqlQuery('SELECT * FROM Section WHERE name = :1', section_name.lower())
                                if (q.count() > 0):
                                    for possible_conflict in q:
                                        if possible_conflict.num != section.num:
                                            errors = errors + 1
                                            section_name_error = 4
                            else:
                                errors = errors + 1
                                section_name_error = 3
                    template_values['section_name'] = section_name
                    template_values['section_name_error'] = section_name_error
                    template_values['section_name_error_message'] = section_name_error_messages[section_name_error]
                    # Verification: title
                    section_title_error = 0
                    section_title_error_messages = ['',
                        u'请输入区域标题',
                        u'区域标题长度不能超过 32 个字符'
                    ]
                    section_title = self.request.get('title').strip()
                    if (len(section_title) == 0):
                        errors = errors + 1
                        section_title_error = 1
                    else:
                        if (len(section_title) > 32):
                            errors = errors + 1
                            section_title_error = 2
                    template_values['section_title'] = section_title
                    template_values['section_title_error'] = section_title_error
                    template_values['section_title_error_message'] = section_title_error_messages[section_title_error]
                    # Verification: title_alternative
                    section_title_alternative_error = 0
                    section_title_alternative_error_messages = ['',
                        u'请输入区域副标题',
                        u'区域标题长度不能超过 32 个字符'
                    ]
                    section_title_alternative = self.request.get('title_alternative').strip()
                    if (len(section_title_alternative) == 0):
                        errors = errors + 1
                        section_title_alternative_error = 1
                    else:
                        if (len(section_title_alternative) > 32):
                            errors = errors + 1
                            section_title_alternative_error = 2
                    template_values['section_title_alternative'] = section_title_alternative
                    template_values['section_title_alternative_error'] = section_title_alternative_error
                    template_values['section_title_alternative_error_message'] = section_title_alternative_error_messages[section_title_alternative_error]
                    # Verification: header
                    section_header_error = 0
                    section_header_error_messages = ['',
                        u'区域头部信息不能超过 1000 个字符'
                    ]
                    section_header = self.request.get('header').strip()
                    if len(section_header) > 1000:
                        errors = errors + 1
                        section_header_error = 1
                    template_values['section_header'] = section_header
                    template_values['section_header_error'] = section_header_error
                    template_values['section_header_error_message'] = section_header_error_messages[section_header_error]
                    # Verification: footer
                    section_footer_error = 0
                    section_footer_error_messages = ['',
                        u'区域尾部信息不能超过 1000 个字符'
                    ]
                    section_footer = self.request.get('footer').strip()
                    if len(section_footer) > 1000:
                        errors = errors + 1
                        section_footer_error = 1
                    template_values['section_footer'] = section_footer
                    template_values['section_footer_error'] = section_footer_error
                    template_values['section_footer_error_message'] = section_footer_error_messages[section_footer_error]
                    template_values['errors'] = errors
                    if (errors == 0):
                        memcache.delete('Section::' + section.name)
                        section.name = section_name
                        section.title = section_title
                        section.title_alternative = section_title_alternative
                        section.header = section_header
                        section.footer = section_footer
                        section.put()
                        memcache.delete('Section_' + str(section.num))
                        memcache.delete('Section::' + section_name)
                        self.redirect('/backstage')
                    else:
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_section.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/backstage')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageNewNodeHandler(webapp.RequestHandler):
    def get(self, section_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                template_values['member'] = CheckAuth(self)
                q = db.GqlQuery("SELECT * FROM Section WHERE name = :1", section_name)
                if (q.count() == 1):
                    template_values['section'] = q[0]
                else:
                    template_values['section'] = False
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_node.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

    def post(self, section_name):
        site = GetSite()
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):        
                template_values['member'] = member
                section = False
                q = db.GqlQuery("SELECT * FROM Section WHERE name = :1", section_name)
                if (q.count() == 1):
                    section = q[0]
                    template_values['section'] = section
                else:
                    template_values['section'] = False
                errors = 0
                # Verification: name
                node_name_error = 0
                node_name_error_messages = ['',
                    u'请输入节点名',
                    u'节点名长度不能超过 32 个字符',
                    u'节点名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个节点名已经存在了']
                node_name = self.request.get('name').strip().lower()
                if (len(node_name) == 0):
                    errors = errors + 1
                    node_name_error = 1
                else:
                    if (len(node_name) > 32):
                        errors = errors + 1
                        node_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', node_name)):
                            q = db.GqlQuery('SELECT __key__ FROM Node WHERE name = :1', node_name.lower())
                            if (q.count() > 0):
                                errors = errors + 1
                                node_name_error = 4
                        else:
                            errors = errors + 1
                            node_name_error = 3
                template_values['node_name'] = node_name
                template_values['node_name_error'] = node_name_error
                template_values['node_name_error_message'] = node_name_error_messages[node_name_error]
                # Verification: title
                node_title_error = 0
                node_title_error_messages = ['',
                    u'请输入节点标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title = self.request.get('title').strip()
                if (len(node_title) == 0):
                    errors = errors + 1
                    node_title_error = 1
                else:
                    if (len(node_title) > 32):
                        errors = errors + 1
                        node_title_error = 2
                template_values['node_title'] = node_title
                template_values['node_title_error'] = node_title_error
                template_values['node_title_error_message'] = node_title_error_messages[node_title_error]
                # Verification: title
                node_title_alternative_error = 0
                node_title_alternative_error_messages = ['',
                    u'请输入节点副标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title_alternative = self.request.get('title_alternative').strip()
                if (len(node_title_alternative) == 0):
                    errors = errors + 1
                    node_title_alternative_error = 1
                else:
                    if (len(node_title_alternative) > 32):
                        errors = errors + 1
                        node_title_alternative_error = 2
                template_values['node_title_alternative'] = node_title_alternative
                template_values['node_title_alternative_error'] = node_title_alternative_error
                template_values['node_title_alternative_error_message'] = node_title_alternative_error_messages[node_title_alternative_error]
                template_values['errors'] = errors
                if (errors == 0):
                    node = Node()
                    q = db.GqlQuery('SELECT * FROM Counter WHERE name = :1', 'node.max')
                    if (q.count() == 1):
                        counter = q[0]
                        counter.value = counter.value + 1
                    else:
                        counter = Counter()
                        counter.name = 'node.max'
                        counter.value = 1
                    node.num = counter.value
                    node.section_num = section.num
                    node.name = node_name
                    node.title = node_title
                    node.title_alternative = node_title_alternative
                    node.put()
                    counter.put()
                    memcache.delete('index_categories')
                    memcache.delete('home_nodes_new')
                    self.redirect('/backstage/node/' + node.name)
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_new_node.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')


class BackstageNodeHandler(webapp.RequestHandler):
    def get(self, node_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):
                template_values['member'] = member
                q = db.GqlQuery("SELECT * FROM Node WHERE name = :1", node_name)
                if (q.count() == 1):
                    node = q[0]
                    if node.parent_node_name is None:
                        siblings = []
                    else:
                        siblings = db.GqlQuery("SELECT * FROM Node WHERE parent_node_name = :1 AND name != :2", node.parent_node_name, node.name)
                    template_values['siblings'] = siblings
                    template_values['node'] = node
                    template_values['node_name'] = node.name
                    template_values['node_title'] = node.title
                    template_values['node_title_alternative'] = q[0].title_alternative
                    if q[0].category is None:
                        template_values['node_category'] = ''
                    else:
                        template_values['node_category'] = q[0].category
                    if q[0].parent_node_name is None:
                        template_values['node_parent_node_name'] = ''
                    else:
                        template_values['node_parent_node_name'] = q[0].parent_node_name
                    if q[0].header is None:
                        template_values['node_header'] = ''
                    else:
                        template_values['node_header'] = q[0].header
                    if q[0].footer is None:
                        template_values['node_footer'] = ''
                    else:
                        template_values['node_footer'] = q[0].footer
                    if q[0].sidebar is None:
                        template_values['node_sidebar'] = ''
                    else:
                        template_values['node_sidebar'] = q[0].sidebar
                    if q[0].sidebar_ads is None:
                        template_values['node_sidebar_ads'] = ''
                    else:
                        template_values['node_sidebar_ads'] = q[0].sidebar_ads
                    template_values['node_topics'] = q[0].topics
                else:
                    template_values['node'] = False
                section = GetKindByNum('Section', node.section_num)
                template_values['section'] = section
                if section is not False:
                    template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + section.title + u' › ' + node.title
                if browser['ios']:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_node.html')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_node.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self, node_name):
        site = GetSite()
        browser = detect(self.request)
        template_values = {}
        template_values['site'] = site
        template_values['system_version'] = SYSTEM_VERSION
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if (member):
            if (member.level == 0):        
                template_values['member'] = member
                node = False
                q = db.GqlQuery("SELECT * FROM Node WHERE name = :1", node_name)
                if (q.count() == 1):
                    node = q[0]
                    template_values['node'] = q[0]
                    template_values['node_name'] = q[0].name
                    template_values['node_title'] = q[0].title
                    template_values['node_title_alternative'] = q[0].title_alternative
                    if q[0].category is None:
                        template_values['node_category'] = ''
                    else:
                        template_values['node_category'] = q[0].category
                    if q[0].parent_node_name is None:
                        template_values['node_parent_node_name'] = ''
                    else:
                        template_values['node_parent_node_name'] = q[0].parent_node_name
                    if q[0].header is None:
                        template_values['node_header'] = ''
                    else:
                        template_values['node_header'] = q[0].header
                    if q[0].footer is None:
                        template_values['node_footer'] = ''
                    else:
                        template_values['node_footer'] = q[0].footer
                    if q[0].sidebar is None:
                        template_values['node_sidebar'] = ''
                    else:
                        template_values['node_sidebar'] = q[0].sidebar
                    if q[0].sidebar_ads is None:
                        template_values['node_sidebar_ads'] = ''
                    else:
                        template_values['node_sidebar_ads'] = q[0].sidebar_ads
                    template_values['node_topics'] = q[0].topics
                else:
                    template_values['node'] = False
                section = False
                q2 = db.GqlQuery("SELECT * FROM Section WHERE num = :1", q[0].section_num)
                if (q2.count() == 1):
                    section = q2[0]
                    template_values['section'] = q2[0]
                else:
                    template_values['section'] = False
                if section is not False:
                    template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + section.title + u' › ' + node.title
                errors = 0
                # Verification: name
                node_name_error = 0
                node_name_error_messages = ['',
                    u'请输入节点名',
                    u'节点名长度不能超过 32 个字符',
                    u'节点名只能由 a-Z 0-9 及 - 和 _ 组成',
                    u'抱歉这个节点名已经存在了']
                node_name = self.request.get('name').strip().lower()
                if (len(node_name) == 0):
                    errors = errors + 1
                    node_name_error = 1
                else:
                    if (len(node_name) > 32):
                        errors = errors + 1
                        node_name_error = 2
                    else:
                        if (re.search('^[a-zA-Z0-9\-\_]+$', node_name)):
                            q = db.GqlQuery('SELECT * FROM Node WHERE name = :1 AND num != :2', node_name.lower(), node.num)
                            if (q.count() > 0):
                                errors = errors + 1
                                node_name_error = 4
                        else:
                            errors = errors + 1
                            node_name_error = 3
                template_values['node_name'] = node_name
                template_values['node_name_error'] = node_name_error
                template_values['node_name_error_message'] = node_name_error_messages[node_name_error]
                # Verification: title
                node_title_error = 0
                node_title_error_messages = ['',
                    u'请输入节点标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title = self.request.get('title').strip()
                if (len(node_title) == 0):
                    errors = errors + 1
                    node_title_error = 1
                else:
                    if (len(node_title) > 32):
                        errors = errors + 1
                        node_title_error = 2
                template_values['node_title'] = node_title
                template_values['node_title_error'] = node_title_error
                template_values['node_title_error_message'] = node_title_error_messages[node_title_error]
                # Verification: title_alternative
                node_title_alternative_error = 0
                node_title_alternative_error_messages = ['',
                    u'请输入节点副标题',
                    u'节点标题长度不能超过 32 个字符'
                ]
                node_title_alternative = self.request.get('title_alternative').strip()
                if (len(node_title_alternative) == 0):
                    errors = errors + 1
                    node_title_alternative_error = 1
                else:
                    if (len(node_title_alternative) > 32):
                        errors = errors + 1
                        node_title_alternative_error = 2
                template_values['node_title_alternative'] = node_title_alternative
                template_values['node_title_alternative_error'] = node_title_alternative_error
                template_values['node_title_alternative_error_message'] = node_title_alternative_error_messages[node_title_alternative_error]
                # Verification: node_category
                node_category = self.request.get('category').strip()
                template_values['node_category'] = node_category
                # Verification: node_parent_node_name
                node_parent_node_name = self.request.get('parent_node_name').strip()
                template_values['node_parent_node_name'] = node_parent_node_name
                # Verification: node_header
                node_header = self.request.get('header').strip()
                template_values['node_header'] = node_header
                # Verification: node_footer
                node_footer = self.request.get('footer').strip()
                template_values['node_footer'] = node_footer
                # Verification: node_sidebar
                node_sidebar = self.request.get('sidebar').strip()
                template_values['node_sidebar'] = node_sidebar
                # Verification: node_sidebar_ads
                node_sidebar_ads = self.request.get('sidebar_ads').strip()
                template_values['node_sidebar_ads'] = node_sidebar_ads
                template_values['errors'] = errors
                if (errors == 0):
                    node.name = node_name
                    node.title = node_title
                    node.title_alternative = node_title_alternative
                    node.category = node_category
                    node.parent_node_name = node_parent_node_name
                    node.header = node_header
                    node.footer = node_footer
                    node.sidebar = node_sidebar
                    node.sidebar_ads = node_sidebar_ads
                    node.put()
                    memcache.delete('Node_' + str(node.num))
                    memcache.delete('Node::' + node.name)
                    memcache.delete('index_categories')
                    memcache.delete('home_nodes_new')
                    self.redirect('/backstage/section/' + section.name)
                else:    
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'mobile', 'backstage_node.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')


class BackstageNodeAvatarHandler(BaseHandler):
    def get(self, node_name):
        self.redirect('/backstage/node/' + node_name)
    
    def post(self, node_name):
        if self.member:
            if self.member.level == 0:
                node = GetKindByName('Node', node_name)
                if node is None:
                    return self.redirect('/backstage')
                dest = '/backstage/node/' + node.name
                timestamp = str(int(time.time()))
                try:
                    avatar = self.request.get('avatar')
                except:
                    return self.redirect(dest)
                if avatar is None:
                    return self.redirect(dest)
                avatar_len = len(avatar)
                if avatar_len == 0:
                    return self.redirect(dest)
                avatar_73 = images.resize(avatar, 73, 73)
                avatar_48 = images.resize(avatar, 48, 48)
                avatar_24 = images.resize(avatar, 24, 24)
                # Large 73x73
                q1 = db.GqlQuery("SELECT * FROM Avatar WHERE name = :1", 'node_' + str(node.num) + '_large')
                if (q1.count() == 1):
                    avatar_large = q1[0]
                    avatar_large.content = db.Blob(avatar_73)
                    avatar_large.put()
                else:
                    qc1 = db.GqlQuery("SELECT * FROM Counter WHERE name = :1", 'avatar.max')
                    if (qc1.count() == 1):
                        counter1 = qc1[0]
                        counter1.value = counter1.value + 1
                    else:
                        counter1 = Counter()
                        counter1.name = 'avatar.max'
                        counter1.value = 1
                    counter1.put()
                    avatar_large = Avatar()
                    avatar_large.name = 'node_' + str(node.num) + '_large'
                    avatar_large.content = db.Blob(avatar_73)
                    avatar_large.num = counter1.value
                    avatar_large.put()
                node.avatar_large_url = '/navatar/' + str(node.num) + '/large?r=' + timestamp
                node.put()
                # Normal 48x48
                q2 = db.GqlQuery("SELECT * FROM Avatar WHERE name = :1", 'node_' + str(node.num) + '_normal')
                if (q2.count() == 1):
                    avatar_normal = q2[0]
                    avatar_normal.content = db.Blob(avatar_48)
                    avatar_normal.put()
                else:
                    qc2 = db.GqlQuery("SELECT * FROM Counter WHERE name = :1", 'avatar.max')
                    if (qc2.count() == 1):
                        counter2 = qc2[0]
                        counter2.value = counter2.value + 1
                    else:
                        counter2 = Counter()
                        counter2.name = 'avatar.max'
                        counter2.value = 1
                    counter2.put()
                    avatar_normal = Avatar()
                    avatar_normal.name = 'node_' + str(node.num) + '_normal'
                    avatar_normal.content = db.Blob(avatar_48)
                    avatar_normal.num = counter2.value
                    avatar_normal.put()
                node.avatar_normal_url = '/navatar/' + str(node.num) + '/normal?r=' + timestamp
                node.put() 
                # Mini 24x24
                q3 = db.GqlQuery("SELECT * FROM Avatar WHERE name = :1", 'node_' + str(node.num) + '_mini')
                if (q3.count() == 1):
                    avatar_mini = q3[0]
                    avatar_mini.content = db.Blob(avatar_24)
                    avatar_mini.put()
                else:
                    qc3 = db.GqlQuery("SELECT * FROM Counter WHERE name = :1", 'avatar.max')
                    if (qc3.count() == 1):
                        counter3 = qc3[0]
                        counter3.value = counter3.value + 1
                    else:
                        counter3 = Counter()
                        counter3.name = 'avatar.max'
                        counter3.value = 1
                    counter3.put()
                    avatar_mini = Avatar()
                    avatar_mini.name = 'node_' + str(node.num) + '_mini'
                    avatar_mini.content = db.Blob(avatar_24)
                    avatar_mini.num = counter3.value
                    avatar_mini.put()
                node.avatar_mini_url = '/navatar/' + str(node.num) + '/mini?r=' + timestamp
                node.put()
                # Upload to MobileMe
                use_this = False
                if config.mobileme_enabled and use_this:
                    headers = {'Authorization' : 'Basic ' + base64.b64encode(config.mobileme_username + ':' + config.mobileme_password)}
                    host = 'idisk.me.com'
                    # Sharding
                    timestamp = str(int(time.time()))
                    shard = node.num % 31
                    root = '/' + config.mobileme_username + '/Web/Sites/v2ex/navatars/' + str(shard)
                    root_mini = root + '/mini'
                    root_normal = root + '/normal'
                    root_large = root + '/large'
                    h = httplib.HTTPConnection(host)
                    # Mini
                    h.request('PUT', root_mini + '/' + str(node.num) + '.png', str(avatar_24), headers)
                    response = h.getresponse()
                    if response.status == 201 or response.status == 204:
                        node.avatar_mini_url = 'http://web.me.com/' + config.mobileme_username + '/v2ex/navatars/' + str(shard) + '/mini/' + str(node.num) + '.png?r=' + timestamp
                    # Normal
                    h.request('PUT', root_normal + '/' + str(node.num) + '.png', str(avatar_48), headers)
                    response = h.getresponse()
                    if response.status == 201 or response.status == 204:
                        node.avatar_normal_url = 'http://web.me.com/' + config.mobileme_username + '/v2ex/navatars/' + str(shard) + '/normal/' + str(node.num) + '.png?r=' + timestamp
                    # Large
                    h.request('PUT', root_large + '/' + str(node.num) + '.png', str(avatar_73), headers)
                    response = h.getresponse()
                    if response.status == 201 or response.status == 204:
                        node.avatar_large_url = 'http://web.me.com/' + config.mobileme_username + '/v2ex/navatars/' + str(shard) + '/large/' + str(node.num) + '.png?r=' + timestamp
                    node.put()
                memcache.set('Node_' + str(node.num), node, 86400 * 14)
                memcache.set('Node::' + node.name, node, 86400 * 14)
                memcache.delete('Avatar::node_' + str(node.num) + '_large')
                memcache.delete('Avatar::node_' + str(node.num) + '_normal')
                memcache.delete('Avatar::node_' + str(node.num) + '_mini')
                #self.session['message'] = '新节点头像设置成功'
                self.redirect(dest)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
        

class BackstageRemoveReplyHandler(webapp.RequestHandler):
    def get(self, reply_key):
        member = CheckAuth(self)
        t = self.request.get('t')
        if (member):
            if (member.level == 0) and (str(member.created_ts) == str(t)):
                reply = db.get(db.Key(reply_key))
                if reply:
                    topic = reply.topic
                    reply.delete()
                    q = db.GqlQuery("SELECT __key__ FROM Reply WHERE topic = :1", topic)
                    topic.replies = q.count()
                    if (topic.replies == 0):
                        topic.last_reply_by = None
                    topic.put()
                    pages = 1
                    memcache.delete('Topic_' + str(topic.num))
                    memcache.delete('topic_' + str(topic.num) + '_replies_desc_compressed')
                    memcache.delete('topic_' + str(topic.num) + '_replies_asc_compressed')
                    memcache.delete('topic_' + str(topic.num) + '_replies_filtered_compressed')
                    memcache.delete('topic_' + str(topic.num) + '_replies_desc_rendered_desktop_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_asc_rendered_desktop_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_filtered_rendered_desktop_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_desc_rendered_ios_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_asc_rendered_ios_' + str(pages))
                    memcache.delete('topic_' + str(topic.num) + '_replies_filtered_rendered_ios_' + str(pages))
                    self.redirect('/t/' + str(topic.num))
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageTidyReplyHandler(webapp.RequestHandler):
    def get(self, reply_num):
        member = CheckAuth(self)
        if (member):
            if (member.level == 0):
                q = db.GqlQuery("SELECT * FROM Reply WHERE num = :1", int(reply_num))
                if (q.count() == 1):
                    reply = q[0]
                    topic_num = reply.topic_num
                    q2 = db.GqlQuery("SELECT * FROM Member WHERE username_lower = :1", reply.created_by.lower())
                    member = q2[0]
                    reply.member = member
                    reply.member_num = member.num
                    q3 = db.GqlQuery("SELECT * FROM Topic WHERE num = :1", topic_num)
                    topic = q3[0]
                    # Begin to do real stuff
                    reply2 = Reply(parent=topic)
                    reply2.num = reply.num
                    reply2.content = reply.content
                    reply2.topic = topic
                    reply2.topic_num = topic.num
                    reply2.member = reply.member
                    reply2.member_num = reply.member_num
                    reply2.created_by = reply.created_by
                    reply2.source = reply.source
                    reply2.created = reply.created
                    reply2.last_modified = reply.last_modified
                    reply2.put()
                    reply.delete()
                    self.redirect('/t/' + str(topic_num))
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
            
class BackstageTidyTopicHandler(webapp.RequestHandler):
    def get(self, topic_num):
        member = CheckAuth(self)
        if (member):
            if (member.level == 0):
                q = db.GqlQuery("SELECT * FROM Topic WHERE num = :1", int(topic_num))
                if (q.count() == 1):
                    topic = q[0]
                    q2 = db.GqlQuery("SELECT * FROM Member WHERE num = :1", topic.member_num)
                    member = q2[0]
                    topic.member = member
                    q3 = db.GqlQuery("SELECT * FROM Node WHERE num = :1", topic.node_num)
                    node = q3[0]
                    topic.node = node
                    topic.put()
                    memcache.delete('Topic_' + str(topic.num))
                    self.redirect('/t/' + str(topic.num))
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageDeactivateUserHandler(webapp.RequestHandler):
    def get(self, key):
        member = CheckAuth(self)
        t = self.request.get('t')
        if member:
            if (member.level == 0) and (str(member.created_ts) == str(t)):
                one = db.get(db.Key(key))
                if one:
                    if one.num != 1:
                        memcache.delete(one.auth)
                        one.deactivated = int(time.time())
                        one.password = hashlib.sha1(str(time.time())).hexdigest()
                        one.auth = hashlib.sha1(str(one.num) + ':' + one.password).hexdigest()
                        one.newbie = 1
                        one.noob = 1
                        one.put()
                        memcache.delete('Member_' + str(one.num))
                        return self.redirect('/member/' + one.username)
        return self.redirect('/')               

class BackstageMoveTopicHandler(webapp.RequestHandler):
    def get(self, key):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        topic = db.get(db.Key(key))
        can_move = False
        ttl = 0
        if member:
            if member.level == 0:
                can_move = True
            if topic:
                if topic.member_num == member.num:
                    now = datetime.datetime.now()
                    ttl = 300 - int((now - topic.created).seconds)
                    if ttl > 0:
                        can_move = True
                        template_values['ttl'] = ttl
        template_values['can_move'] = can_move
        if member:
            template_values['member'] = member
            if can_move:
                template_values['page_title'] = site.title + u' › 移动主题'
                template_values['site'] = site
                if topic is not None:
                    node = topic.node
                    template_values['topic'] = topic
                    template_values['node'] = node
                    template_values['system_version'] = SYSTEM_VERSION
                    themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                    template_values['themes'] = themes
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_move_topic.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
    
    def post(self, key):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        topic = db.get(db.Key(key))
        can_move = False
        ttl = 0
        if member:
            if member.level == 0:
                can_move = True
            if topic:
                if topic.member_num == member.num:
                    now = datetime.datetime.now()
                    ttl = 300 - int((now - topic.created).seconds)
                    if ttl > 0:
                        can_move = True
                        template_values['ttl'] = ttl
        template_values['can_move'] = can_move
        if member:
            template_values['member'] = member
            if can_move:
                template_values['page_title'] = site.title + u' › 移动主题'
                template_values['site'] = site
                if topic is not None:
                    errors = 0
                    node = topic.node
                    template_values['topic'] = topic
                    template_values['node'] = node
                    template_values['system_version'] = SYSTEM_VERSION
                    destination = self.request.get('destination')
                    if destination is not None:
                        node_new = GetKindByName('Node', destination)
                        if node_new is not False:
                            node_new = db.get(node_new.key())
                            node_old = topic.node
                            node_old.topics = node_old.topics - 1
                            node_old.put()
                            node_new.topics = node_new.topics + 1
                            node_new.put()
                            topic.node = node_new
                            topic.node_num = node_new.num
                            topic.node_name = node_new.name
                            topic.node_title = node_new.title
                            topic.put()
                            memcache.delete('Topic_' + str(topic.num))
                            memcache.delete('Node_' + str(node_old.num))
                            memcache.delete('Node_' + str(node_new.num))
                            memcache.delete('Node::' + str(node_old.name))
                            memcache.delete('Node::' + str(node_new.name))
                            memcache.delete('q_latest_16')
                            memcache.delete('home_rendered')
                            memcache.delete('home_rendered_mobile')
                            self.redirect('/t/' + str(topic.num))
                        else:
                            errors = errors + 1
                    else:
                        errors = errors + 1
                    if errors > 0:
                        themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                        template_values['themes'] = themes
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_move_topic.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/')
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')
        
class BackstageSiteHandler(webapp.RequestHandler):
    def get(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › 站点设置'
                template_values['site'] = site
                template_values['site_title'] = site.title
                template_values['site_slogan'] = site.slogan
                template_values['site_domain'] = site.domain
                template_values['site_description'] = site.description
                if site.home_categories is not None:
                    template_values['site_home_categories'] = site.home_categories
                else:
                    template_values['site_home_categories'] = ''
                if site.analytics is not None:
                    template_values['site_analytics'] = site.analytics
                else:
                    template_values['site_analytics'] = ''
                if site.topic_view_level is not None:
                    template_values['site_topic_view_level'] = site.topic_view_level
                else:
                    template_values['site_topic_view_level'] = -1
                if site.topic_create_level is not None:
                    template_values['site_topic_create_level'] = site.topic_create_level
                else:
                    template_values['site_topic_create_level'] = 1000
                if site.topic_reply_level is not None:
                    template_values['site_topic_reply_level'] = site.topic_reply_level
                else:
                    template_values['site_topic_reply_level'] = 1000
                if site.meta is not None:
                    template_values['site_meta'] = site.meta
                else:
                    template_values['site_meta'] = ''
                if site.home_top is not None:
                    template_values['site_home_top'] = site.home_top
                else:
                    template_values['site_home_top'] = ''
                if site.theme is not None:
                    template_values['site_theme'] = site.theme
                else:
                    template_values['site_theme'] = 'default'
                if site.data_migration_mode is not None:
                    template_values['site_data_migration_mode'] = site.data_migration_mode
                else:
                    template_values['site_data_migration_mode'] = 0
                s = GetLanguageSelect(site.l10n)
                template_values['s'] = s
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                template_values['themes'] = themes
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_site.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
        else:
            self.redirect('/')
    
    def post(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › 站点设置'
                template_values['site'] = site
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                errors = 0
                # Verification: title (required)
                site_title_error = 0
                site_title_error_messages = ['',
                    u'请输入站点名',
                    u'站点名长度不能超过 40 个字符'
                ]
                site_title = self.request.get('title').strip()
                if (len(site_title) == 0):
                    errors = errors + 1
                    site_title_error = 1    
                else:
                    if (len(site_title) > 40):
                        errors = errors + 1
                        site_title_error = 1
                template_values['site_title'] = site_title
                template_values['site_title_error'] = site_title_error
                template_values['site_title_error_message'] = site_title_error_messages[site_title_error]
                # Verification: slogan (required)
                site_slogan_error = 0
                site_slogan_error_messages = ['',
                    u'请输入站点标语',
                    u'站点标语长度不能超过 140 个字符'
                ]
                site_slogan = self.request.get('slogan').strip()
                if (len(site_slogan) == 0):
                    errors = errors + 1
                    site_slogan_error = 1    
                else:
                    if (len(site_slogan) > 140):
                        errors = errors + 1
                        site_slogan_error = 1
                template_values['site_slogan'] = site_slogan
                template_values['site_slogan_error'] = site_slogan_error
                template_values['site_slogan_error_message'] = site_slogan_error_messages[site_slogan_error]
                # Verification: domain (required)
                site_domain_error = 0
                site_domain_error_messages = ['',
                    u'请输入主要域名',
                    u'主要域名长度不能超过 40 个字符'
                ]
                site_domain = self.request.get('domain').strip()
                if (len(site_domain) == 0):
                    errors = errors + 1
                    site_domain_error = 1    
                else:
                    if (len(site_domain) > 40):
                        errors = errors + 1
                        site_domain_error = 1
                template_values['site_domain'] = site_domain
                template_values['site_domain_error'] = site_domain_error
                template_values['site_domain_error_message'] = site_domain_error_messages[site_domain_error]
                # Verification: description (required)
                site_description_error = 0
                site_description_error_messages = ['',
                    u'请输入站点简介',
                    u'站点简介长度不能超过 200 个字符'
                ]
                site_description = self.request.get('description').strip()
                if (len(site_description) == 0):
                    errors = errors + 1
                    site_description_error = 1    
                else:
                    if (len(site_description) > 200):
                        errors = errors + 1
                        site_description_error = 1
                template_values['site_description'] = site_description
                template_values['site_description_error'] = site_description_error
                template_values['site_description_error_message'] = site_description_error_messages[site_description_error]
                # Verification: analytics (optional)
                site_analytics_error = 0
                site_analytics_error_messages = ['',
                    u'Analytics ID 格式不正确'
                ]
                site_analytics = self.request.get('analytics').strip()
                if len(site_analytics) > 0:
                    if re.findall('^UA\-[0-9]+\-[0-9]+$', site_analytics):
                        site_analytics_error = 0
                    else:
                        errors = errors + 1
                        site_analytics_error = 1
                else:
                    site_analytics = ''
                template_values['site_analytics'] = site_analytics
                template_values['site_analytics_error'] = site_analytics_error
                template_values['site_analytics_error_message'] = site_analytics_error_messages[site_analytics_error]
                # Verification: l10n (required)
                site_l10n = self.request.get('l10n').strip()
                supported = GetSupportedLanguages()
                if site_l10n == '':
                    site_l10n = site.l10n
                else:
                    if site_l10n not in supported:
                        site_l10n = site.l10n
                s = GetLanguageSelect(site_l10n)
                template_values['s'] = s
                template_values['site_l10n'] = site_l10n
                # Verification: home_categories (optional)
                site_home_categories_error = 0
                site_home_categories_error_messages = ['',
                    u'首页分类信息不要超过 2000 个字符'
                ]
                site_home_categories = self.request.get('home_categories').strip()
                site_home_categories_length = len(site_home_categories)
                if len(site_home_categories) > 0:
                    if site_home_categories_length > 2000:
                        errors = errors + 1
                        site_home_categories_error = 1
                else:
                    site_home_categories = ''
                template_values['site_home_categories'] = site_home_categories
                template_values['site_home_categories_error'] = site_home_categories_error
                template_values['site_home_categories_error_message'] = site_home_categories_error_messages[site_home_categories_error]
                # Verification: topic_view_level (default=-1)
                site_topic_view_level = self.request.get('topic_view_level')
                try:
                    site_topic_view_level = int(site_topic_view_level)
                    if site_topic_view_level < -1:
                        site_topic_view_level = -1
                except:
                    site_topic_view_level = -1
                template_values['site_topic_view_level'] = site_topic_view_level
                # Verification: topic_create_level (default=1000)
                site_topic_create_level = self.request.get('topic_create_level')
                try:
                    site_topic_create_level = int(site_topic_create_level)
                    if site_topic_create_level < -1:
                        site_topic_create_level = 1000
                except:
                    site_topic_create_level = 1000
                template_values['site_topic_create_level'] = site_topic_create_level
                # Verification: topic_reply_level (default=1000)
                site_topic_reply_level = self.request.get('topic_reply_level')
                try:
                    site_topic_reply_level = int(site_topic_reply_level)
                    if site_topic_reply_level < -1:
                        site_topic_reply_level = 1000
                except:
                    site_topic_reply_level = 1000
                template_values['site_topic_reply_level'] = site_topic_reply_level
                # Verification: meta
                site_meta = self.request.get('meta')
                template_values['site_meta'] = site_meta
                # Verification: home_top
                site_home_top = self.request.get('home_top')
                template_values['site_home_top'] = site_home_top
                # Verification: theme
                site_theme = self.request.get('theme')
                themes = os.listdir(os.path.join(os.path.dirname(__file__), 'tpl', 'themes'))
                template_values['themes'] = themes
                if site_theme in themes:
                    template_values['site_theme'] = site_theme
                else:
                    site_theme = 'default'
                    template_values['site_theme'] = site_theme
                # Verification: data_migration_mode
                site_data_migration_mode = self.request.get('data_migration_mode')
                if site_data_migration_mode == 'on':
                    template_values['site_data_migration_mode'] = 1
                else:
                    template_values['site_data_migration_mode'] = 0
                
                template_values['errors'] = errors
                
                if errors == 0:
                    site.title = site_title
                    site.slogan = site_slogan
                    site.domain = site_domain
                    site.description = site_description
                    if site_home_categories != '':
                        site.home_categories = site_home_categories
                    if site_analytics != '':
                        site.analytics = site_analytics
                    site.l10n = site_l10n
                    site.topic_view_level = site_topic_view_level
                    site.topic_create_level = site_topic_create_level
                    site.topic_reply_level = site_topic_reply_level
                    site.meta = site_meta
                    site.home_top = site_home_top
                    site.theme = site_theme
                    site.data_migration_mode = template_values['site_data_migration_mode']
                    site.put()
                    memcache.delete('index_categories')
                    template_values['message'] = l10n.site_settings_updated;
                    template_values['site'] = site
                    memcache.delete('site')
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_site.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
        else:
            self.redirect('/')

class BackstageTopicHandler(webapp.RequestHandler):
    def get(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + l10n.topic_settings.decode('utf-8')
                template_values['site'] = site
                template_values['site_use_topic_types'] = site.use_topic_types
                if site.topic_types is None:
                    template_values['site_topic_types'] = ''
                else:
                    template_values['site_topic_types'] = site.topic_types
                if site.use_topic_types is not True:
                    s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                else:
                    s = '<select name="use_topic_types"><option value="1" selected="selected">Enabled</option><option value="0">Disabled</option></select>'
                template_values['s'] = s
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_topic.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
        else:
            self.redirect('/')

    def post(self):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + l10n.topic_settings.decode('utf-8')
                template_values['site'] = site
                template_values['site_use_topic_types'] = site.use_topic_types
                if site.topic_types is None:
                    template_values['site_topic_types'] = ''
                else:
                    template_values['site_topic_types'] = site.topic_types
                if site.use_topic_types is not True:
                    s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                else:
                    s = '<select name="use_topic_types"><option value="1" selected="selected">Enabled</option><option value="0">Disabled</option></select>'
                template_values['s'] = s
                template_values['member'] = member
                template_values['system_version'] = SYSTEM_VERSION
                errors = 0
                # Verification: use_topic_types
                site_use_topic_types = self.request.get('use_topic_types').strip()
                if site_use_topic_types is None:
                    s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                else:
                    if site_use_topic_types == '1':
                        s = '<select name="use_topic_types"><option value="1" selected="selected">Enabled</option><option value="0">Disabled</option></select>'
                    else:
                        s = '<select name="use_topic_types"><option value="1">Enabled</option><option value="0" selected="selected">Disabled</option></select>'
                template_values['s'] = s
                # Verification: topic_types
                site_topic_types = self.request.get('topic_types').strip()
                if errors == 0:
                    if site_use_topic_types == '1':
                        site.use_topic_types = True
                    else:
                        site.use_topic_types = False
                    site.topic_types = site_topic_types
                    site.put()
                    memcache.delete('site')
                    self.redirect('/backstage')
                else:
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_topic.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
        else:
            self.redirect('/')


class BackstageRemoveMemcacheHandler(webapp.RequestHandler):
    def post(self):
        member = CheckAuth(self)
        if member:
            if member.level == 0:
                mc = self.request.get('mc')
                if mc is not None:
                    memcache.delete(mc)
        self.redirect('/backstage')


class BackstageMemberHandler(webapp.RequestHandler):
    def get(self, member_username):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                member_username_lower = member_username.lower()
                q = db.GqlQuery("SELECT * FROM Member WHERE username_lower = :1", member_username_lower)
                if (q.count() == 1):
                    one = q[0]
                    template_values['one'] = one
                    errors = 0
                    template_values['one_username'] = one.username
                    template_values['one_email'] = one.email
                    if one.avatar_large_url is None:
                        template_values['one_avatar_large_url'] = ''
                    else:
                        template_values['one_avatar_large_url'] = one.avatar_large_url
                    if one.avatar_normal_url is None:
                        template_values['one_avatar_normal_url'] = ''
                    else:
                        template_values['one_avatar_normal_url'] = one.avatar_normal_url
                    if one.avatar_mini_url is None:
                        template_values['one_avatar_mini_url'] = ''
                    else:
                        template_values['one_avatar_mini_url'] = one.avatar_mini_url
                    if one.bio is None:
                        template_values['one_bio'] = ''
                    else:
                        template_values['one_bio'] = one.bio
                    template_values['one_level'] = one.level
                    template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + one.username
                    template_values['site'] = site
                    template_values['member'] = member
                    template_values['system_version'] = SYSTEM_VERSION
                    template_values['latest_members'] = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT 5")
                    path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_member.html')
                    output = template.render(path, template_values)
                    self.response.out.write(output)
                else:
                    self.redirect('/backstage')
                
        else:
            self.redirect('/')
            

    def post(self, member_username):
        template_values = {}
        site = GetSite()
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                member_username_lower = member_username.lower()
                q = db.GqlQuery("SELECT * FROM Member WHERE username_lower = :1", member_username_lower)
                if (q.count() == 1):
                    one = q[0]
                    template_values['one'] = one
                    errors = 0
                    # Verification: username
                    one_username_error = 0
                    one_username_error_messages = ['',
                        l10n.username_empty,
                        l10n.username_too_long,
                        l10n.username_too_short,
                        l10n.username_invalid,
                        l10n.username_taken]
                    one_username = self.request.get('username').strip()
                    if (len(one_username) == 0):
                        errors = errors + 1
                        one_username_error = 1
                    else:
                        if (len(one_username) > 32):
                            errors = errors + 1
                            one_username_error = 2
                        else:
                            if (len(one_username) < 3):
                                errors = errors + 1
                                one_username_error = 3
                            else:
                                if (re.search('^[a-zA-Z0-9\_]+$', one_username)):
                                    q = db.GqlQuery('SELECT * FROM Member WHERE username_lower = :1 AND num != :2', one_username.lower(), one.num)
                                    if (q.count() > 0):
                                        errors = errors + 1
                                        one_username_error = 5
                                else:
                                    errors = errors + 1
                                    one_username_error = 4
                    template_values['one_username'] = one_username
                    template_values['one_username_error'] = one_username_error
                    template_values['one_username_error_message'] = one_username_error_messages[one_username_error]
                    # Verification: email
                    one_email_error = 0
                    one_email_error_messages = ['',
                        u'请输入电子邮件地址',
                        u'电子邮件地址长度不能超过 32 个字符',
                        u'输入的电子邮件地址不符合规则',
                        u'这个电子邮件地址已经有人注册过了']
                    one_email = self.request.get('email').strip()
                    if (len(one_email) == 0):
                        errors = errors + 1
                        one_email_error = 1
                    else:
                        if (len(one_email) > 32):
                            errors = errors + 1
                            one_email_error = 2
                        else:
                            p = re.compile(r"(?:^|\s)[-a-z0-9_.]+@(?:[-a-z0-9]+\.)+[a-z]{2,6}(?:\s|$)", re.IGNORECASE)
                            if (p.search(one_email)):
                                q = db.GqlQuery('SELECT * FROM Member WHERE email = :1 AND num != :2', one_email.lower(), one.num)
                                if (q.count() > 0):
                                    errors = errors + 1
                                    one_email_error = 4
                            else:
                                errors = errors + 1
                                one_email_error = 3
                    template_values['one_email'] = one_email.lower()
                    template_values['one_email_error'] = one_email_error
                    template_values['one_email_error_message'] = one_email_error_messages[one_email_error]
                    # Verification: avatar
                    one_avatar_large_url = self.request.get('avatar_large_url')
                    template_values['one_avatar_large_url'] = one_avatar_large_url
                    one_avatar_normal_url = self.request.get('avatar_normal_url')
                    template_values['one_avatar_normal_url'] = one_avatar_normal_url
                    one_avatar_mini_url = self.request.get('avatar_mini_url')
                    template_values['one_avatar_mini_url'] = one_avatar_mini_url
                    # Verification: bio
                    one_bio = self.request.get('bio')
                    template_values['one_bio'] = one_bio
                    # Verification: level
                    one_level = self.request.get('level')
                    try:
                        one_level = int(one_level)
                    except:
                        if one.num == 1:
                            one_level = 0
                        else:
                            one_level = 1000
                    template_values['one_level'] = one_level
                    if errors == 0:
                        one.username = one_username
                        one.username_lower = one_username.lower()
                        one.email = one_email
                        one.avatar_large_url = one_avatar_large_url
                        one.avatar_normal_url = one_avatar_normal_url
                        one.avatar_mini_url = one_avatar_mini_url
                        one.bio = one_bio
                        one.level = one_level
                        one.put()
                        memcache.delete('Member_' + str(one.num))
                        memcache.delete('Member::' + one_username.lower())
                        self.redirect('/backstage')
                    else:
                        template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › ' + one.username
                        template_values['site'] = site
                        template_values['member'] = member
                        template_values['system_version'] = SYSTEM_VERSION
                        template_values['latest_members'] = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT 5")
                        path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_member.html')
                        output = template.render(path, template_values)
                        self.response.out.write(output)
                else:
                    self.redirect('/backstage')

        else:
            self.redirect('/')

class BackstageMembersHandler(webapp.RequestHandler):
    def get(self):
        template_values = {}
        site = GetSite()
        template_values['site'] = site
        member = CheckAuth(self)
        l10n = GetMessages(self, member, site)
        template_values['l10n'] = l10n
        if member:
            if member.level == 0:
                template_values['member'] = member
                template_values['page_title'] = site.title + u' › ' + l10n.backstage.decode('utf-8') + u' › 浏览所有会员'
                member_total = memcache.get('member_total')
                if member_total is None:
                    q3 = db.GqlQuery("SELECT * FROM Counter WHERE name = 'member.total'")
                    if (q3.count() > 0):
                        member_total = q3[0].value
                    else:
                        member_total = 0
                    memcache.set('member_total', member_total, 600)
                template_values['member_total'] = member_total
                page_size = 60
                pages = 1
                if member_total > page_size:
                    if (member_total % page_size) > 0:
                        pages = int(math.floor(member_total / page_size)) + 1
                    else:
                        pages = int(math.floor(member_total / page_size))
                try:
                    page_current = int(self.request.get('p'))
                    if page_current < 1:
                        page_current = 1
                    if page_current > pages:
                        page_current = pages
                except:
                    page_current = 1
                page_start = (page_current - 1) * page_size
                template_values['pages'] = pages
                template_values['page_current'] = page_current
                i = 1
                ps = []
                while i <= pages:
                    ps.append(i)
                    i = i + 1
                template_values['ps'] = ps
                q = db.GqlQuery("SELECT * FROM Member ORDER BY created DESC LIMIT " + str(page_start )+ "," + str(page_size))
                template_values['members'] = q
                path = os.path.join(os.path.dirname(__file__), 'tpl', 'desktop', 'backstage_members.html')
                output = template.render(path, template_values)
                self.response.out.write(output)
            else:
                self.redirect('/')
        else:
            self.redirect('/signin')

class BackstageRemoveNotificationHandler(BaseHandler):
    def get(self, key):
        o = db.get(db.Key(key))
        if o and self.member:
            if type(o).__name__ == 'Notification':
                if o.for_member_num == self.member.num:
                    o.delete()
                    memcache.delete('nn::' + self.member.username_lower)
        self.redirect('/notifications')

def main():
    application = webapp.WSGIApplication([
    ('/backstage', BackstageHomeHandler),
    ('/backstage/new/minisite', BackstageNewMinisiteHandler),
    ('/backstage/minisite/(.*)', BackstageMinisiteHandler),
    ('/backstage/remove/minisite/(.*)', BackstageRemoveMinisiteHandler),
    ('/backstage/new/page/(.*)', BackstageNewPageHandler),
    ('/backstage/page/(.*)', BackstagePageHandler),
    ('/backstage/remove/page/(.*)', BackstageRemovePageHandler),
    ('/backstage/new/section', BackstageNewSectionHandler),
    ('/backstage/section/(.*)', BackstageSectionHandler),
    ('/backstage/new/node/(.*)', BackstageNewNodeHandler),
    ('/backstage/node/([a-z0-9A-Z]+)', BackstageNodeHandler),
    ('/backstage/node/([a-z0-9A-Z]+)/avatar', BackstageNodeAvatarHandler),
    ('/backstage/remove/reply/(.*)', BackstageRemoveReplyHandler),
    ('/backstage/tidy/reply/([0-9]+)', BackstageTidyReplyHandler),
    ('/backstage/tidy/topic/([0-9]+)', BackstageTidyTopicHandler),
    ('/backstage/deactivate/user/(.*)', BackstageDeactivateUserHandler),
    ('/backstage/move/topic/(.*)', BackstageMoveTopicHandler),
    ('/backstage/site', BackstageSiteHandler),
    ('/backstage/topic', BackstageTopicHandler),
    ('/backstage/remove/mc', BackstageRemoveMemcacheHandler),
    ('/backstage/member/(.*)', BackstageMemberHandler),
    ('/backstage/members', BackstageMembersHandler),
    ('/backstage/remove/notification/(.*)', BackstageRemoveNotificationHandler),
    ],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()
#!/usr/bin/env python # coding=utf-8 # Verification: name # Verification: title # Verification: description # Verification: name # Verification: title # Verification: content # Verification: mode # Verification: content_type # Verification: weight # Delete all contents # Delete the minisite # Verification: name # Verification: title # Verification: content # Verification: mode # Verification: content_type # Verification: weight # Verification: name # Verification: title # Verification: title # Verification: name # Verification: title # Verification: title_alternative # Verification: header # Verification: footer # Verification: name # Verification: title # Verification: title # Verification: name # Verification: title # Verification: title_alternative # Verification: node_category # Verification: node_parent_node_name # Verification: node_header # Verification: node_footer # Verification: node_sidebar # Verification: node_sidebar_ads # Large 73x73 # Normal 48x48 # Mini 24x24 # Upload to MobileMe # Sharding # Mini # Normal # Large #self.session['message'] = '新节点头像设置成功' # Begin to do real stuff # Verification: title (required) # Verification: slogan (required) # Verification: domain (required) # Verification: description (required) # Verification: analytics (optional) # Verification: l10n (required) # Verification: home_categories (optional) # Verification: topic_view_level (default=-1) # Verification: topic_create_level (default=1000) # Verification: topic_reply_level (default=1000) # Verification: meta # Verification: home_top # Verification: theme # Verification: data_migration_mode # Verification: use_topic_types # Verification: topic_types # Verification: username # Verification: email # Verification: avatar # Verification: bio # Verification: level