Commits

ronald martinez committed ad59672

ok

Comments (0)

Files changed (165)

celerybeat-schedule

Binary file added.

controllers/__init__.py

+import logging
+
+from models import User
+from tornado.web import RequestHandler
+
+
+class BaseHandler(RequestHandler):
+
+    def __init__(self, *args, **kwargs):
+        super(BaseHandler, self).__init__(*args, **kwargs)
+
+    def get_current_user(self):
+        _user = self.get_secure_cookie("user")
+        if _user:
+            try:
+                _user = User.objects.get(_user, consistent_read=True)
+            except Exception as exc:
+                logging.error(exc)
+            else:
+                return _user
+        return None
+
+    def render_string(self, template, **kwargs):
+        kwargs.update({'handler': self})
+        return self.settings.get('template_env')\
+            .get_template(template).render(**kwargs)
+
+    def render(self, template, **kwargs):
+        self.set_header('cache-control', 'no-cache')
+        kwargs['user'] = self.get_current_user()
+        self.finish(self.render_string(template, **kwargs))

controllers/api.py

+import logging
+import datetime
+
+from models import ApiUser, ApiProduct, Category
+from controllers import BaseHandler
+from utils import check_email
+
+
+class Login(BaseHandler):
+
+    def get(self, **kwargs):
+        self.render('api/login.html', **kwargs)
+
+    def post(self):
+
+        status_code = 0
+        email = self.get_argument('email', '')
+        password = self.get_argument('password', '')
+        token = ''
+
+        if len(email) < 5 or len(password) < 1:
+            status_code = 1
+        elif not check_email(email):
+            status_code = 1
+
+        if status_code == 0:
+
+            def expiration_date():
+                return (datetime.datetime.now() + \
+                        datetime.timedelta(days=2)).strftime(
+                            '%Y-%m-%dT%H:%M:%S')
+
+            if not ApiUser.email_exists(email):
+
+                user = ApiUser()
+                user.email = email
+                user.password = password
+                user.expiration_date = expiration_date()
+                user.token = ApiUser.generate_token()
+                token = user.token
+
+                try:
+                    user.save()
+                except Exception as exc:
+                    logging.error(exc)
+                    status_code = 2
+            else:
+
+                if not ApiUser.auth(email, password):
+                    status_code = 3
+                    logging.info('auth fail!')
+                else:
+                    user = ApiUser.objects.get(email)
+                    user.expiration_date = expiration_date()
+                    token = user.token
+
+                    try:
+                        user.update()
+                    except Exception as exc:
+                        logging.error(exc)
+                        status_code = 2
+
+        self.finish(dict(status_code=status_code, token=token))
+
+
+class AddProduct(BaseHandler):
+
+    def get(self, **kwargs):
+        kwargs['action'] = 'new'
+        self.render('api/product.html', **kwargs)
+
+    def post(self):
+
+        status_code = 0
+        token = self.get_argument('token', '')
+        product_id = ''
+
+        if len(token) < 1:
+            status_code = 1
+            logging.info('no token')
+        else:
+            user = ApiUser.get_user_by_token(token)
+            if not user:
+                status_code = 1
+                logging.error('not user')
+            else:
+                if user.has_expires():
+                    status_code = 2
+                    logging.error('has expires')
+                else:
+                    try:
+                        _raw_image = self.request.files['filename'][0]
+                    except Exception as exc:
+                        logging.error(exc)
+                        status_code = 3
+
+        if status_code == 0:
+            product = ApiProduct()
+
+            try:
+                product.save()
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 4
+            else:
+
+                product_id = product.id
+                url = product.upload_img(_raw_image.get('body'))
+
+                if not url:
+                    status_code = 5
+                    logging.error('not upload')
+                else:
+                    product.image = url
+                    logging.info('url: %s' % url)
+
+                    try:
+                        product.update()
+                    except Exception as exc:
+                        logging.error(exc)
+                        status_code = 4
+
+        self.finish(dict(status_code=status_code,
+            product_id=product_id))
+
+
+class EditProduct(BaseHandler):
+
+    def get(self, id, **kwargs):
+
+        try:
+            product = ApiProduct.objects.get(id)
+        except:
+            self.send_error(404)
+            return
+
+        if not product.title:
+            product.title = ''
+
+        if not product.description:
+            product.description = ''
+
+        if not product.location:
+            product.location = ''
+
+        if product.published_at:
+            try:
+                product.published_at = product.published_at.date()
+            except Exception as exc:
+                logging.error(exc)
+        else:
+            product.published_at = ''
+
+        if product.expires_at:
+            try:
+                product.expires_at = product.expires_at.date()
+            except Exception as exc:
+                logging.error(exc)
+        else:
+            product.expires_at = ''
+
+        categories = Category.objects.all()
+
+        if product.categories:
+            for x, y in enumerate(categories):
+                if y.title.lower() in product.categories:
+                    categories[x].checked = True
+                else:
+                    categories[x].checked = False
+
+        kwargs['product'] = product
+        kwargs['categories'] = categories
+        kwargs['audiences'] = ApiProduct.AUDIENCES_TYPES
+        kwargs['action'] = 'edit'
+        self.render('api/product.html', **kwargs)
+
+    def post(self, id):
+
+        status_code = 0
+
+        categories = self.get_arguments('categories', None)
+        title = self.get_argument('title', '')
+        description = self.get_argument('description', '')
+        cost = self.get_argument('cost', 0)
+        will_travel = self.get_argument('will_travel', 0)
+        allow_retailers = self.get_argument('allow_retailers', None)
+        allow_charities = self.get_argument('allow_charities', None)
+        donate_now = self.get_argument('donate_now', None)
+        published_at = self.get_argument('published_at', '')
+        expires_at = self.get_argument('expires_at', '')
+        location = self.get_argument('location', '')
+        audience = self.get_argument('audience', '')
+        token = self.get_argument('token', '')
+        type = self.get_argument('type', None)
+
+        product_id = ''
+
+        try:
+            will_travel = int(will_travel)
+        except Exception as exc:
+            logging.error(exc)
+            will_travel = 0
+
+        try:
+            cost = int(cost)
+        except Exception as exc:
+            logging.error(exc)
+            cost = 0
+
+        if len(token) < 1:
+            status_code = 1
+            logging.info('no token')
+        else:
+            user = ApiUser.get_user_by_token(token)
+
+            if not user:
+                self.send_error(404)
+                return
+            else:
+                if user.has_expires():
+                    status_code = 2
+                    logging.error('has expires')
+
+        if status_code == 0:
+
+            try:
+                product = ApiProduct.objects.get(id)
+            except Exception as exc:
+                self.send_error(404)
+                return
+
+            product_id = product.id
+
+            if len(title) < 1 or len(description) < 1 or len(published_at) < 1:
+                status_code = 1
+            elif not type in ('have', 'want'):
+                status_code = 1
+
+            if status_code == 0:
+                try:
+                    published_at = datetime.datetime.strptime(
+                        published_at, '%Y-%m-%d')
+                except ValueError as exc:
+                    logging.error(exc)
+                    status_code = 3
+
+                try:
+                    expires_at = datetime.datetime.strptime(
+                        expires_at, '%Y-%m-%d')
+                except ValueError as exc:
+                    logging.error(exc)
+                    status_code = 3
+
+            if status_code == 0:
+                if not categories:
+                    status_code = 4
+
+            if status_code == 0:
+                try:
+                    _raw_image = self.request.files['filename'][0]
+                except (KeyError, IndexError) as exc:
+                    _raw_image = None
+
+                product.title = title
+                product.description = description
+                product.cost = cost
+                product.will_travel = will_travel
+                product.allow_charities = True if allow_charities else False
+                product.allow_retailers = True if allow_retailers else False
+                product.donate_now = True if donate_now else False
+                product.published_at = published_at
+                product.expires_at = expires_at
+                product.type = type
+                product.user = user.email
+                product.categories = categories
+                product.location = location
+                product.audience = audience
+                product.status = 'active'
+                product.set_slug(title)
+
+                try:
+                    product.update()
+                except Exception as exc:
+                    logging.error(exc)
+                    status_code = 5
+                else:
+                    
+                    if _raw_image:
+                        url = product.upload_img(_raw_image.get('body'))
+
+                        if not url:
+                            status_code = 6
+                            logging.error('not upload')
+                        else:
+                            product.image = url
+                            logging.info('url: %s' % url)
+
+                            try:
+                                product.update()
+                            except Exception as exc:
+                                logging.error(exc)
+                                status_code = 7
+
+        self.finish(dict(status_code=status_code,
+            product_id=product_id))

controllers/home.py

+import simpledb
+import logging
+
+from models import Product, Category, User
+from controllers import BaseHandler
+
+
+class Index(BaseHandler):
+
+    def get(self, slug=None):
+        user = self.get_current_user()
+
+        id_want = self.get_argument('id_want', None)
+        id_have = self.get_argument('id_have', None)
+        #id_want = '53148fb1-262d-4dfe-b2f4-9ad84858c710'
+        product_have = None
+        product_want = None
+
+        products_have = Product.objects.filter(type='have', status='active')
+        products_want = Product.objects.filter(type='want', status='active')
+
+        if slug:
+            products_have = products_have.filter(categories__in=[slug])
+            products_want = products_want.filter(categories__in=[slug])
+
+        if id_want:
+            product_want = Product.objects.get(id_want)
+
+        if id_have:
+            product_have = Product.objects.get(id_have)
+
+        self.render('site/home.html',
+            user=user,
+            products_have=products_have,
+            products_want=products_want,
+            product_have=product_have,
+            product_want=product_want,
+            categories=Category.objects.all()
+        )
+
+
+class Search(BaseHandler):
+
+    def get(self):
+
+        allow_charities = self.get_argument('allow_charities', None)
+        user = self.get_argument('user', None)
+        type = self.get_argument('type', None)
+        category = self.get_argument('category', None)
+
+        products = Product.objects.filter(type=type, status='active')
+
+        if user:
+            user = self.get_current_user()
+            if hasattr(user, 'email'):
+                products = products.filter(user=user.email)
+
+        if allow_charities:
+            products = products.filter(allow_charities=str(True))
+
+        if category:
+            products = products.filter(
+                simpledb.where(categories__in=[category])
+            )
+
+        try:
+            data = [dict(
+                        username=User.objects.get(x.user).name,
+                        title=x.title,
+                        image=x.image,
+                        slug=x.slug,
+                        description=x.description,
+                        cost=x.cost,
+                        will_travel=x.will_travel,
+                        expires_at=x.expires,
+                        categories=[y.title for y in  x.data_categories]
+                    ) for x in products]
+        except Exception as exc:
+            logging.error(exc)
+            data = []
+
+        self.finish(dict(data=data))

controllers/product.py

+import logging
+import datetime
+
+from models import Product, Category, Match, Conversation, Comment, User
+from controllers import BaseHandler
+from tornado.web import authenticated
+from tasks import generate_thumbs
+
+
+class Add(BaseHandler):
+
+    @authenticated
+    def get(self, **kwargs):
+        self.render('product.html', **kwargs)
+
+    @authenticated
+    def post(self):
+        status_code = 0
+
+        try:
+            _raw_image = self.request.files['filename'][0]
+        except (KeyError, IndexError) as exc:
+            logging.error(exc)
+            status_code = 1
+        else:
+            product = Product()
+
+            try:
+                product.save()
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 2
+            else:
+
+                if not product.upload_img(_raw_image.get('body')):
+                    status_code = 3
+                    logging.error('no upload image')
+                else:
+
+                    from boto.sqs.connection import SQSConnection
+                    from boto.sqs.message import Message
+                    import settings
+
+                    conn = SQSConnection(settings.AWS_KEY, settings.AWS_SECRET)
+                    q = conn.create_queue('generate_thumbs')
+                    m = Message()
+                    m.set_body(product.id)
+
+                    
+                    try:
+                        status = q.write(m)
+                    except Exception as exc:
+                        logging.error(exc)
+                        status_code = 4
+                    else:
+                        if not status:
+                            status_code = 4
+
+                    #generate_thumbs.delay(product.id)
+                    self.redirect(self.reverse_url('product_edit', product.id))
+                    return
+
+        self.get(status_code=status_code)
+
+
+class Edit(BaseHandler):
+
+    @authenticated
+    def get(self, id, **kwargs):
+        user = self.get_current_user()
+
+        try:
+            product = Product.objects.get(id)
+        except:
+            self.send_error(404)
+            return
+
+        if not product.title:
+            product.title = 'product'
+
+        if not product.description:
+            product.description = 'This is a brief description..'
+
+        if not product.cost:
+            product.cost = 50
+
+        if not product.will_travel:
+            product.will_travel = 1000
+
+        if product.published_at:
+            try:
+                product.published_at = product.published_at.date()
+            except Exception as exc:
+                logging.error(exc)
+        else:
+            product.published_at = datetime.datetime.now().strftime('%Y-%m-%d')
+
+        if product.expires_at:
+            try:
+                product.expires_at = product.expires_at.date()
+            except Exception as exc:
+                logging.error(exc)
+        else:
+            product.expires_at = (datetime.datetime.now() + \
+                datetime.timedelta(days=5)).strftime('%Y-%m-%d')
+
+        if not product.location:
+            product.location = 'WC 12 avenue'
+
+        categories = Category.objects.all()
+
+        if not product.categories:
+            product.categories = [u'metarials', u'sporting']
+
+        if product.categories:
+            for x, y in enumerate(categories):
+                if y.title.lower() in product.categories:
+                    categories[x].checked = True
+                else:
+                    categories[x].checked = False
+
+        logging.info('image: %s' % product.image)
+        logging.info('tyny_image: %s' % product.tiny_url)
+        logging.info('small_image: %s' % product.small_url)
+        logging.info('large_image: %s' % product.large_url)
+        logging.info('medium_image: %s' % product.medium_url)
+
+        kwargs['product'] = product
+        kwargs['categories'] = categories
+        kwargs['audiences'] = Product.AUDIENCES_TYPES
+        kwargs['user'] = user
+        kwargs['action'] = 'edit'
+        self.render('product.html', **kwargs)
+
+    @authenticated
+    def post(self, id):
+        status_code = 0
+
+        categories = self.get_arguments('categories', None)
+        title = self.get_argument('title', '')
+        description = self.get_argument('description', '')
+        cost = self.get_argument('cost', '')
+        will_travel = self.get_argument('will_travel', '')
+        allow_retailers = self.get_argument('allow_retailers', None)
+        allow_charities = self.get_argument('allow_charities', None)
+        donate_now = self.get_argument('donate_now', None)
+        published_at = self.get_argument('published_at', '')
+        expires_at = self.get_argument('expires_at', '')
+        type = self.get_argument('type', None)
+        location = self.get_argument('location', '')
+        audience = self.get_argument('audience', '')
+
+        try:
+            will_travel = int(will_travel)
+        except Exception as exc:
+            logging.error(exc)
+            will_travel = 0
+
+        try:
+            cost = int(cost)
+        except Exception as exc:
+            logging.error(exc)
+            cost = 0
+
+        user = self.get_current_user()
+
+        if not user:
+            self.send_error(404)
+
+        try:
+            product = Product.objects.get(id)
+        except Exception as exc:
+            self.send_error(404)
+
+        if len(title) < 1 or len(description) < 1 or len(published_at) < 1:
+            status_code = 1
+        elif not type in ('have', 'want'):
+            status_code = 1
+
+        if status_code == 0:
+            try:
+                published_at = datetime.datetime.strptime(
+                    published_at, '%Y-%m-%d')
+            except ValueError as exc:
+                logging.error(exc)
+                status_code = 2
+
+            logging.info(expires_at)
+
+            try:
+                expires_at = datetime.datetime.strptime(
+                    expires_at, '%Y-%m-%d')
+            except ValueError as exc:
+                logging.error(exc)
+                status_code = 2
+
+        if status_code == 0:
+            if not categories:
+                status_code = 4
+
+        if status_code == 0:
+            try:
+                _raw_image = self.request.files['filename'][0]
+            except (KeyError, IndexError) as exc:
+                _raw_image = None
+
+            product.title = title
+            product.description = description
+            product.cost = cost
+            product.will_travel = will_travel
+            product.allow_charities = True if allow_charities else False
+            product.allow_retailers = True if allow_retailers else False
+            product.donate_now = True if donate_now else False
+            product.published_at = published_at
+            product.expires_at = expires_at
+            product.type = type
+            product.user = user.email
+            product.categories = categories
+            product.location = location
+            product.audience = audience
+            product.status = 'active'
+            product.set_slug(title)
+
+            try:
+                product.update()
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 5
+
+            if status_code == 0:
+                if _raw_image:
+
+                    if not product.upload_img(_raw_image.get('body')):
+                        status_code = 4
+                    else:
+                        generate_thumbs.delay(product.id)
+
+                    if status_code == 0:
+                        self.redirect(self.reverse_url('product_edit',
+                            product.id))
+                        return
+
+        self.get(id, status_code=status_code)
+
+
+class View(BaseHandler):
+
+    def initialize(self):
+        self.have_comments = False
+
+    def get(self, slug, conversation_id=None):
+
+        tot_unread_comments = 0
+        conversations = []
+        comments = []
+        is_owner = False
+
+        try:
+            product = Product.objects.filter(slug=slug)[0]
+        except Exception as exc:
+            logging.error(exc)
+            self.send_error(404)
+            return
+
+        user = self.get_current_user()
+
+        if user:
+            is_owner = True if user.email == product.user else False
+
+            logging.info('is_owner: %s' % is_owner)
+            logging.info('current_user: %s' % user.email)
+            logging.info('product_owner: %s' % product.user)
+
+            if not is_owner:
+                conversation = product.get_conversation(user.email)
+
+                if conversation:
+
+                    comments = [dict(user=x.user_data.name,
+                        text=x.description,
+                        created_at=x.created_at_f) \
+                            for x in conversation.comments]
+            else:
+
+                if not self.have_comments:
+
+                    for c in product.conversations:
+                        tot_unread_comments += int(c.unread_comments)
+                        conversations.append(dict(id=c.id,
+                            user=c.user_data.name,
+                            unread_comments=c.unread_comments))
+                else:
+
+                    try:
+                        comments = [dict(user=x.user_data.name,
+                            text=x.description,
+                            created_at=x.created_at_f) \
+                                for x in Comment.objects.filter(
+                                    conversation=conversation_id)]
+                    except Exception as exc:
+                        logging.error(exc)
+
+                    try:
+                        conversation = Conversation.objects.get(
+                            conversation_id)
+                    except Exception as exc:
+                        logging.error(exc)
+                    else:
+                        conversation.unread_comments = 0
+
+                        try:
+                            conversation.update()
+                        except Exception as exc:
+                            logging.error(exc)
+
+        self.render('site/product.html',
+            product=product,
+            is_owner=is_owner,
+            comments=comments,
+            conversations=conversations,
+            have_comments=self.have_comments,
+            tot_unread_comments=tot_unread_comments)
+
+    def post(self, slug, conversation_id=None):
+
+        try:
+            product = Product.objects.filter(slug=slug)[0]
+        except:
+            self.send_error(404)
+            return
+
+        status_code = 0
+
+        user = self.get_current_user()
+        message = self.get_argument('message', '')
+        product_id = self.get_argument('product_id', None)
+
+        logging.info('from_user: %s' % user.email)
+        logging.info('to_user: %s' % product.user)
+        logging.info('product: %s' % product.slug)
+
+        if product.user == user.email:
+            logging.info('the same user!')
+            status_code = 3
+        else:
+            if len(message) < 3:
+                status_code = 1
+            else:
+                try:
+                    conversation = Conversation.objects.filter(
+                        product=product_id,
+                        with_user=user.email
+                    )
+                except Exception as exc:
+                    logging.error(exc)
+                else:
+                    try:
+                        conversation = conversation[0]
+                    except:
+                        pass
+
+                if not conversation:
+                    conversation = Conversation()
+                    conversation.product = product_id
+                    conversation.with_user = user.email
+
+                    try:
+                        conversation.save()
+                    except Exception as exc:
+                        logging.error(exc)
+                        status_code = 2
+
+                comment = Comment()
+                comment.description = message
+                comment.conversation = conversation.id
+                comment.user = user.email
+
+                try:
+                    comment.save()
+                except Exception as exc:
+                    logging.error(exc)
+                    status_code = 2
+                else:
+                    conversation.unread_comments = int(
+                        conversation.unread_comments) + 1
+
+                    try:
+                        conversation.update()
+                    except Exception as exc:
+                        logging.error(exc)
+                        status_code = 3
+
+        logging.info('status_code: %s' % status_code)
+        self.get(slug)
+
+
+class ViewComments(View):
+
+    def initialize(self):
+        self.have_comments = True
+
+    def post(self, slug, conversation_id=None):
+        status_code = 0
+
+        user = self.get_current_user()
+        message = self.get_argument('message', '')
+        to_user = self.get_argument('to_user', None)
+
+        try:
+            to_user = User.objects.get(to_user)
+        except Exception as exc:
+            logging.error(exc)
+            self.send_error(404)
+
+        try:
+            product = Product.objects.filter(slug=slug)[0]
+        except:
+            self.send_error(404)
+            return
+
+        if len(message) < 3:
+            status_code = 1
+        else:
+            conversation = Conversation.objects.filter(
+                product=product.id,
+                with_user=to_user.email
+            )[0]
+
+            if not conversation:
+                self.send_error(404)
+
+            comment = Comment()
+            comment.description = message
+            comment.conversation = conversation.id
+            comment.user = user.email
+
+            try:
+                comment.save()
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 2
+
+        logging.info('status_code: %s' % status_code)
+        self.get(slug, conversation_id)
+
+
+class MatchItems(BaseHandler):
+
+    @authenticated
+    def get(self):
+        status_code = 0
+
+        user = self.get_current_user()
+        product_1 = self.get_argument('product_1', None)
+        product_2 = self.get_argument('product_2', None)
+
+        if product_1 == product_2:
+            status_code = 1
+        else:
+            try:
+                product_1 = Product.objects.get(product_1)
+            except Exception as exc:
+                self.send_error(404)
+
+            try:
+                product_2 = Product.objects.get(product_2)
+            except Exception as exc:
+                self.send_error(404)
+
+            match = Match.objects.filter(
+                source=product_1.id,
+                target=product_2.id,
+                user=user.email
+            )
+
+            if len(match) < 1:
+                match = Match()
+                match.source = product_1.id
+                match.target = product_2.id
+                match.user = user.email
+
+                try:
+                    match.save()
+                except Exception as exc:
+                    logging.error(exc)
+                    status_code = 2
+                else:
+                    user.score = int(user.score) + 1
+
+                    try:
+                        user.update()
+                    except Exception as exc:
+                        logging.error(exc)
+                        status_code = 4
+                    else:
+                        logging.info('update score')
+            else:
+                status_code = 3
+
+        self.finish(dict(status_code=status_code))

controllers/user.py

+import logging
+import settings
+
+from tornado.auth import FacebookGraphMixin
+from models import User
+from controllers import BaseHandler
+from tornado.web import authenticated, asynchronous
+from tasks import send_email
+from utils import check_email
+
+
+class Add(BaseHandler):
+
+    def get(self, **kwargs):
+        self.render('user.html', **kwargs)
+
+    def post(self):
+        status_code = 0
+        name = self.get_argument('name', '')
+        lastname = self.get_argument('lastname', '')
+        gender = self.get_argument('gender', None)
+        password = self.get_argument('password', '')
+        confirm_password = self.get_argument('confirm_password', '')
+        email = self.get_argument('email', '')
+
+        if len(name) < 1 or len(lastname) < 1 or \
+            len(password) < 1 or len(email) < 1:
+            status_code = 1
+        elif not (password == confirm_password):
+            status_code = 2
+        elif not check_email(email):
+            status_code = 3
+        elif not gender in ('male', 'female'):
+            status_code = 4
+        elif User.email_exists(email):
+            status_code = 5
+
+        if status_code == 0:
+            user = User()
+            user.email = email
+            user.password = password
+            user.name = name
+            user.lastname = lastname
+            user.gender = gender
+            user.activation = User.get_token('activation')
+            user.activation_passwd = User.get_token('activation_passwd')
+
+            try:
+                user.save()
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 6
+            else:
+                content = self.render_string(
+                    "mail/confirmation.html",
+                    first_name=name,
+                    last_name=lastname,
+                    url=self.reverse_url("user_activate",
+                        user.activation),
+                    settings=self.settings
+                )
+
+                mail = dict(sender=settings.AWS_EMAIL_FROM,
+                    subject='Registration confirmation',
+                    body=content,
+                    to=['m4cf1.server@gmail.com']
+                )
+
+                send_email.delay(mail)
+                status_code = 7
+
+        self.get(status_code=status_code)
+
+
+class Edit(BaseHandler):
+
+    @authenticated
+    def get(self, **kwargs):
+        self.render('user.html', **kwargs)
+
+    @authenticated
+    def post(self):
+        status_code = 0
+        name = self.get_argument('name', '')
+        lastname = self.get_argument('lastname', '')
+        gender = self.get_argument('gender', None)
+        password = self.get_argument('password', '')
+        confirm_password = self.get_argument('confirm_password', '')
+        user = self.get_current_user()
+
+        if len(name) < 1 or len(lastname) < 1:
+            status_code = 1
+        elif len(password) > 0:
+            if not (password == confirm_password):
+                status_code = 2
+        elif gender not in ('male', 'female'):
+            status_code = 4
+
+        if status_code == 0:
+            if password:
+                user.set_password(password)
+
+            user.name = name
+            user.lastname = lastname
+            user.gender = gender
+
+            try:
+                user.update()
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 6
+            else:
+                status_code = 8
+
+        self.get(status_code=status_code)
+
+
+class Activate(BaseHandler):
+    def get(self, token):
+        try:
+            user = User.objects.filter(activation=token)[0]
+        except Exception as exc:
+            logging.error(exc)
+            self.send_error(404)
+            return
+        else:
+            user.status = 'active'
+            user.token = ''
+
+            try:
+                user.update()
+            except Exception as exc:
+                logging.error(exc)
+                self.send_error(409)
+                return
+
+        self.set_secure_cookie('user', user.email)
+        self.redirect(self.reverse_url("home"))
+        return
+
+
+class Login(BaseHandler):
+
+    def get(self, **kwargs):
+        self.render('login.html', **kwargs)
+
+    def post(self):
+        status_code = 0
+        email = self.get_argument('email', '')
+        password = self.get_argument('password', '')
+
+        if len(email) < 5 or len(password) < 1:
+            status_code = 1
+        elif not check_email(email):
+            status_code = 1
+
+        if status_code == 0:
+            if User.auth(email, password):
+                self.set_secure_cookie('user', email)
+                self.redirect(self.reverse_url('home'))
+                return
+            else:
+                status_code = 2
+
+        self.get(status_code=status_code)
+
+
+class LoginFacebook(FacebookGraphMixin, BaseHandler):
+
+    @asynchronous
+    def get(self):
+        url = "%s://%s%s" % (
+            self.request.protocol,
+            self.request.host,
+            self.reverse_url("user_login_fb")
+        )
+
+        if self.get_argument('code', None):
+            self.get_authenticated_user(
+                redirect_uri=url,
+                client_id=self.settings['facebook_api_key'],
+                client_secret=self.settings['facebook_secret'],
+                code=self.get_argument('code'),
+                callback=self._on_auth,
+            )
+            return
+
+        self.authorize_redirect(
+            redirect_uri=url,
+            client_id=self.settings['facebook_api_key'],
+            extra_params={"scope": "email"}
+        )
+
+    def _on_auth(self, user):
+        if not user:
+            self.send_error(500)
+        else:
+            self.facebook_request(
+                '/me',
+                self._on_stream,
+                access_token=user['access_token']
+            )
+        return
+
+    def _on_stream(self, data):
+        if not data:
+            self.send_error(500)
+            return
+
+        save_ok = True
+        email = data['email']
+
+        if not User.email_exists(email):
+            logging.info('save fb_user')
+            user = User()
+            user.email = email
+            user.name = data['first_name']
+            user.lastname = '%s %s' % (
+                data['middle_name'], data['last_name'])
+            user.gender = data['gender']
+            user.facebook_id = data['id']
+            user.status = 'active'
+
+            try:
+                user.save()
+            except Exception as exc:
+                save_ok = False
+                logging.error(exc)
+        else:
+            logging.info('exits email')
+            user = User.objects.get(email)
+
+            if not user.facebook_id:
+                logging.info('exists email but not fbid')
+                user.facebook_id = data.get('id')
+
+                try:
+                    user.update()
+                except Exception as exc:
+                    save_ok = False
+                    logging.error(exc)
+
+        if save_ok:
+            self.set_secure_cookie('user', email)
+            self.redirect(self.reverse_url('home'))
+        else:
+            self.render('login.html', status_code=2)
+        return
+
+
+class Logout(BaseHandler):
+
+    def get(self):
+        self.clear_cookie("user")
+        self.redirect(self.reverse_url('home'))
+
+
+class ForgotPassword(BaseHandler):
+
+    def get(self, **kwargs):
+        self.render('forgot_password.html', **kwargs)
+
+    def post(self):
+        status_code = 0
+        email = self.get_argument('email', '')
+
+        if len(email) < 4 or not check_email(email):
+            status_code = 1
+        else:
+            try:
+                user = User.objects.get(email)
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 2
+            else:
+                user.activation_passwd = User.get_token('activation_passwd')
+
+                try:
+                    user.update()
+                except Exception as exc:
+                    logging.error(exc)
+                else:
+                    content = self.render_string(
+                        "mail/change_password.html",
+                        first_name=user.name,
+                        last_name=user.lastname,
+                        url=self.reverse_url("user_change_password",
+                                user.activation_passwd),
+                        settings=self.settings
+                    )
+
+                    # override for testing
+                    email = 'm4cf1.server@gmail.com'
+
+                    mail = dict(sender=settings.AWS_EMAIL_FROM,
+                        subject='Change password',
+                        body=content,
+                        to=[email]
+                    )
+
+                    send_email.delay(mail)
+                    status_code = 3
+
+        self.get(status_code=status_code)
+
+
+class ChangePassword(BaseHandler):
+
+    def get(self, token, **kwargs):
+        try:
+            user = User.objects.filter(activation_passwd=token)[0]
+        except:
+            self.send_error(405)
+            return
+        else:
+            self.set_cookie('token_pwd', user.activation_passwd)
+        self.render('change_password.html', **kwargs)
+
+    def post(self, token, **kwargs):
+        status_code = 0
+        password = self.get_argument('password', '')
+        confirm_password = self.get_argument('confirm_password', '')
+
+        try:
+            user = User.objects.filter(activation_passwd=token)[0]
+        except:
+            self.send_error(405)
+            return
+
+        if len(password) < 4 or len(confirm_password) < 4:
+            status_code = 1
+        elif not (password == confirm_password):
+            status_code = 2
+
+        if status_code == 0:
+            user.set_password(password)
+
+            try:
+                user.update()
+            except Exception as exc:
+                logging.error(exc)
+                status_code = 3
+            else:
+                self.clear_cookie('token_pwd')
+                status_code = 4
+
+        self.get(token, status_code=status_code)

create_categories.py

+from models import Category
+
+CATEGORIES = ('APLIANCES', 'ANTIQUES', 'BARKER', 'BIKES', 'BOATS', 'BOOKS',
+'BUSINESS', 'COMPUTER', 'FREE', 'FURNITURE', 'GENERAL', 'JEWELRY',
+'METARIALS', 'RVS', 'SPORTING', 'TICKETS', 'TOOLS', 'WANTED')
+
+for x in CATEGORIES:
+    cat = Category()
+    cat.title = x
+    cat.status = 'enabled'
+    cat.save()
+#from boto.s3.connection import S3Connection
+import settings
+
+"""
+cn = S3Connection(
+    settings.AWS_KEY, settings.AWS_SECRET
+)
+"""
+
+#cn.delete_domain('api')
+
+
+
+from simpledb import SimpleDB
+
+sdb = SimpleDB(settings.AWS_KEY, settings.AWS_SECRET)
+
+del sdb['product']
+

frontend/build.js

+function building() {
+  var build = require('building');
+  
+  var destino = __dirname + '/..';
+  build.prepare({
+    remove: [
+      destino + '/static'
+    ],
+    create: [
+      destino + '/static/js',
+      //destino + '/static/js/libs',
+      destino + '/static/css'
+    ]
+  });
+
+
+  // template
+  build.templates({
+    jade: { 
+      pretty: true
+    },
+    origin: __dirname + '/templates',
+    destino: destino + '/templates/site',
+    validFile: function(file) {
+      return file.indexOf('_') === -1 &&
+        file.indexOf('layout') === -1 &&
+        file.indexOf('base.jade') === -1;
+    }
+  });
+
+  //build.javascript({
+    //origin: __dirname + '/static/js/site.home.js',
+    //destino: destino + '/static/js/site.home.js'
+  //});
+
+  //build.copy(
+    //__dirname + '/static/js/libs/',
+     //destino + '/static/js/libs/'
+  //);
+  build.copy(
+    __dirname + '/static/js/',
+     destino + '/static/js/'
+  );
+
+
+  build.styles({
+    origin: __dirname + '/static/css/site.styl',
+    destino: destino + '/static/css/site.css'
+  });
+
+  build.copy(
+    __dirname + '/static/images',
+     destino + '/static/images'
+  );
+
+  build.copy(
+    __dirname + '/static/fonts',
+     destino + '/static/fonts'
+  );
+}
+
+exports.building = building;
+
+building();

frontend/node_modules/building/index.js

+(function() {
+  var fs = require('fs');
+  var util = require('util');
+  var jade = require('jade');
+  var mkdirp = require('mkdirp');
+  var uglifyjs = require('uglify-js');
+  var findit = require('findit');
+  var stylus = require('stylus');
+  var path = require('path');
+  var basename = path.basename;
+  var dirname = path.dirname;
+  var resolve = path.resolve;
+  var wrench = require('wrench');
+  
+  var color = require('color');
+
+  /* Recorre el sistema de archivos buscando carpetas y archivos */
+  function FI() {
+    var self = this;
+
+    self.re = /.*/;
+
+    self.path = __dirname + '/static';
+
+    self.onFile = function() {
+    };
+
+    self.init = function(path) {
+      fs.lstat(path, function(err, stat) {
+        if (err) {
+          throw err;
+        }
+
+        if (stat.isFile() && self.re.test(path)) {
+          fs.readFile(path, 'utf8', function(err, str) {
+            if (err) {
+              throw err;
+            }
+
+            if (typeof self.onFile === 'function') {
+              self.onFile(path, str);
+            }
+          });
+        }
+
+        else if (stat.isDirectory()) {
+          fs.readdir(path, function(err, files) {
+            if (err) {
+              throw err;
+            }
+
+            files.map(function(filename) {
+              return path + '/' + filename;
+            })
+            .forEach(self.init);
+          });
+        }
+      });
+    }
+  }
+
+  /* copia y pega archivos */
+  function copy(src, dst, cb) {
+    if (fs.lstatSync(src).isDirectory()) {
+      wrench.copyDirSyncRecursive(src, dst);
+    }
+
+    else {
+      fs.stat(dst, _copy);
+    }
+
+    return;
+
+    function _copy(err) {
+      var is, os;
+
+      if (!err) {
+        if (cb) {
+          return cb(new Error("File " + dst + " exists."));
+        }
+        else {
+          console.log(new Error("File " + dst + " exists."));
+        }
+      }
+
+      fs.stat(src, function (err) {
+        if (err) {
+          return cb(err);
+        }
+        is = fs.createReadStream(src);
+        os = fs.createWriteStream(dst);
+        util.pump(is, os, cb);
+      });
+    }
+  }
+
+  /* exporta archivos jade a html */
+  function templates(opt) {
+    opt = opt || {};
+    var origin = opt.origin || __dirname + '/templates';
+    var destino = opt.destino || __dirname + '/build';
+    var build_ext_file = opt.build_ext_file || '.html';
+      
+    var cjade = opt.jade || {};
+    cjade.layout = cjade.layoud || false;
+    cjade.prety = cjade.prety || true;
+    cjade.time = cjade.time || function() {
+      return new Date().getTime()
+    };
+    
+
+    var w = new FI();
+    w.onFile = function(file, str) {
+      if (typeof opt.validFile === 'function' && opt.validFile(file) === true) {
+        var options = cjade;
+        options.filename = file;
+
+        //var options = {
+          //filename: file,
+          //pretty: opt.pretty || false,
+          //local: {
+            //debug: false,
+            //noCache: new Date().getTime(),
+            //time: function() {
+              //return new Date().getTime();
+            //},
+            //options: opt.options || {}
+          //}
+        //};
+
+        var fn = jade.compile(str, options);
+        var nfile = file.split(origin).join(destino);
+
+        if (file.indexOf('inmueble') !== -1) {
+          nfile = nfile.split('.jade').join('.jinja');
+        }
+
+        else if (build_ext_file) {
+          nfile = nfile.split('.jade').join(build_ext_file);
+        }
+
+        else {
+          nfile = nfile.split('.jade').join('.html');
+        }
+
+        var dir = resolve(dirname(nfile));
+
+        mkdirp(dir, 0755, function(err) {
+          if (err) {
+            throw err;
+          }
+
+          fs.writeFile(nfile, fn(options), function(err) {
+            if (err) {
+              throw err;
+            }
+            console.log(
+              color.set('Template', 'blue'),
+              color.key('export', file),
+              color.key('to', nfile));
+          });
+        });
+      }
+
+      else {
+        console.log(
+          color.set('Template', 'blue'),
+          color.key('skip', file, 'red')
+        );
+      }
+    };
+
+    w.init(origin);
+  }
+
+  /* minimizar javascript */
+  function minJS(file, debug) {
+    var jsp = uglifyjs.parser;
+    var pro = uglifyjs.uglify;
+
+    var orig_code = fs.readFileSync(file, 'utf8');
+
+    if (debug) {
+      return orig_code;
+    }
+
+    var ast = jsp.parse(orig_code); // parse code and get the initial AST
+    ast = pro.ast_mangle(ast); // get a new AST with mangled names
+    ast = pro.ast_squeeze(ast); // get an AST with compression optimizations
+    return pro.gen_code(ast); // compressed code here
+  }
+  
+  function javascript(opt) {
+    opt = opt || {};
+    var origin = opt.origin;
+    var destino = opt.destino;
+
+    findit.find(origin, function(file) {
+
+      if (file.indexOf('.js') !== -1 && file.indexOf(opt.exclude) === -1) {
+
+        var final_code = minJS(file);
+        var destino_file = file.split(origin).join(destino);
+
+        fs.writeFile(destino_file, final_code, function(err) {
+          if (err) throw err;
+          console.log(
+            color.set('JS', 'blue'), 
+            color.key('min', file),
+            color.key('to', destino_file)
+            );
+        });
+      }
+
+      else {
+        console.log(
+          color.set('JS', 'blue'), 
+          color.key('skip', file, 'red')
+        );
+      }
+    });
+  }
+
+  function merge(opt) {
+    opt = opt || {};
+    var origin = opt.origin;
+    var destino = opt.destino;
+    var final_code = '';
+    var i = 0;
+
+    for (i; i < origin.length; ++i) {
+      final_code += fs.readFileSync(origin[i], 'utf8');
+    }
+
+    fs.writeFileSync(destino, final_code, 'utf8');
+
+    console.log(
+      color.key('merge', '[' + origin.join(',\n') + ']'),
+      color.key('to', destino)
+    );
+
+    if (typeof opt.callback === 'function') {
+      opt.callback();
+    }
+  }
+  
+  function styles(opt) {
+    opt = opt || {};
+    var origin = opt.origin;
+    var destino = opt.destino;
+
+    var site = fs.readFileSync(origin, 'utf8');
+    stylus(site)
+      .set('filename', origin)
+      .set('compress', opt.compress || true)
+      .render(function(err, css){
+        if (err) throw err;
+
+        fs.writeFile(destino, css, function(err) {
+          if (err) throw err;
+          console.log(
+            color.set('Estilos', 'blue'), 
+            color.key('copy', origin),
+            color.key('->', destino)
+            );
+        });
+      });
+  }
+
+  function prepare(opt) {
+    var i;
+
+    try {
+      // eliminar
+      if (opt.remove && opt.remove.length > 0) {
+        for (i in opt.remove) {
+          if (
+            opt.remove.hasOwnProperty(i) &&
+            fs.lstatSync(opt.remove[i]).isDirectory()
+          ) {
+            wrench.rmdirSyncRecursive(opt.remove[i]);
+          }
+        }
+      }
+    }
+    catch(e) {
+      console.log(e);
+    }
+
+    try {
+      // crear
+      if (opt.create && opt.create.length > 0) {
+        for (i in opt.create) {
+          wrench.mkdirSyncRecursive(opt.create[i]);
+        }
+      }
+    }
+    catch(e) {
+      console.log(e);
+    }
+  }
+  
+
+  exports.templates = templates;
+  exports.javascript = javascript;
+  exports.styles = styles;
+  exports.prepare = prepare;
+  exports.copy = copy;
+
+}).call(this);

frontend/node_modules/color/index.js

+(function() {
+  var colors = {
+    default: '\033[0m',
+    gray: '\033[90m',
+    cyan: '\033[36m',
+    red: '\033[31m',
+    green: '\033[32m',
+    blue: '\033[34m',
+    yellow: '\033[33m'
+  };
+
+  function set (text, color) {
+    return colors[color] + text + colors.default;
+  }
+
+  function key(key, value) {
+    return '  ' + set(key + ' : ', 'gray') + set(value, 'green');
+  }
+
+  exports.set = set;
+  exports.key = key;
+
+}).call(this);
+

frontend/package.json

+{
+    "name": "vuulo frontend"
+  , "version": "0.0.1"
+  , "private": true
+  , "dependencies": {
+      "express": "2.5.8"
+    , "jade": ">= 0.0.1"
+    , "stylus": ">= 0.27.x"
+    , "walk": ">= 2.2.x"
+  }
+}

frontend/server.js

+
+/**
+ * Module dependencies.
+ */
+
+var express = require('express')
+  , stylus = require('stylus');
+  
+
+var app = module.exports = express.createServer();
+
+// Configuration
+app.use(stylus.middleware({
+  debug: true,
+  src: __dirname,
+  dest: __dirname,
+  compile: function(str) {
+    return stylus(str, {
+      compress: true
+    });
+  }
+}));
+
+app.configure(function(){
+  app.set('views', __dirname);
+  app.set('view options', {
+    layout: false,
+    prety: true,
+    local: {
+      noCache: new Date().getTime()
+    }
+  });
+  app.set('view engine', 'jade');
+  app.use(express.static(__dirname));
+});
+
+// Routes
+app.get('/', function(rep, res) {
+  res.render(__dirname + '/templates/home.jade');
+});
+
+var port = 8000;
+var host = '127.0.0.1';
+
+if (process.argv.indexOf('-h') !== -1) {
+  host = process.argv[process.argv.indexOf('-h') + 1];
+}
+
+if (process.argv.indexOf('-p') !== -1) {
+  port = process.argv[process.argv.indexOf('-p') + 1];
+}
+
+// server
+app.listen(port, host, function(){
+  console.log("Express server listening address %s on port %d in %s mode", app.address().address, app.address().port, app.settings.env);
+});

frontend/static/css/site.css

+@font-face{font-family:'helveticaneuebold';src:url("../static/fonts/helveticaneuebold.eot");src:url("../static/fonts/helveticaneuebold.eot?#iefix") format('embedded-opentype'),url("../fonts/helveticaneuebold.woff") format('woff'),url("../fonts/helveticaneuebold.ttf") format('truetype');font-weight:normal;font-style:normal}
+@font-face{font-family:'helveticaneuelight';src:url("../static/fonts/helveticaneuelight.eot");src:url("../static/fonts/helveticaneuelight.eot?#iefix") format('embedded-opentype'),url("../fonts/helveticaneuelight.woff") format('woff'),url("../fonts/helveticaneuelight.ttf") format('truetype');font-weight:normal;font-style:normal}
+article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block}
+audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
+audio:not([controls]){display:none}
+[hidden]{display:none}
+html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
+html,button,input,select,textarea{font-family:sans-serif}
+body{margin:0}
+a:focus{outline:thin dotted}
+a:hover,a:active{outline:0}
+h1{font-size:2em;margin:0}
+h2{font-size:1.5em;margin:0}
+h3{font-size:1.17em;margin:1em 0}
+h4{font-size:1em;margin:0}
+h5{font-size:.83em;margin:0}
+h6{font-size:.75em;margin:0}
+abbr[title]{border-bottom:1px dotted}
+b,strong{font-weight:bold}
+blockquote{margin:1em 40px}
+dfn{font-style:italic}
+mark{background:#ff0;color:#000}
+p,pre{margin:0}
+pre,code,kbd,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}
+pre{white-space:pre}
+pre{white-space:pre-wrap;word-wrap:break-word}
+q{quotes:none}
+q:before,q:after{content:''}
+q:before,q:after{content:none}
+small{font-size:75%}
+sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
+sup{top:-.5em}
+sub{bottom:-.25em}
+dl,menu,ol,ul{margin:0;list-style:none}
+dd{margin:0 0 0 40px}
+menu,ol,ul{padding:0 0 0 0}
+nav ul,nav ol{list-style:none;list-style-image:none}
+img{border:0;-ms-interpolation-mode:bicubic}
+svg:not(:root){overflow:hidden}
+figure{margin:0}
+form{margin:0}
+fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
+legend{border:0;padding:0;white-space:normal;*margin-left:-7px}
+button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}
+button,input{line-height:normal}
+button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}
+button[disabled],input[disabled]{cursor:default}
+input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*height:13px;*width:13px}
+input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
+input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
+button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
+textarea{overflow:auto;vertical-align:top}
+table{border-collapse:collapse;border-spacing:0}
+a{color:#1f7fc4}
+body{color:#888}
+textarea{resize:none;outline:none}
+body{background:#ffe8ca url("../images/site/bgBody.jpg") repeat-x 0 0}
+#wrap{margin:0 auto;width:1000px;height:700px}
+#header{position:relative;height:100px}
+#logo{position:absolute;top:35px;left:33px}
+#btn_logout{background:url("../images/site/btn-LogOut.png") no-repeat;display:block;position:absolute;top:0;right:63px;width:127px;height:30px}
+#search{background:url("../images/site/btn-search.jpg") no-repeat;position:absolute;right:54px;bottom:21px;width:230px;height:30px;}
+#search #search_submit,#search #search_input{display:block;background-color:transparent;border:none;outline:none}
+#search #search_submit{background:none;float:left;margin:0;padding:0;width:35px;height:29px;text-indent:-9999em}
+#search #search_input{float:right;padding-top:8px;width:197px;font-family:'helveticaneuelight';font-weight:normal;font-size:13px;line-height:17px;color:#666}
+#nav-points{height:42px;overflow:hidden;margin:0 auto;padding:2px 29px 0;zoom:1;}
+#nav-points .nav{float:left;padding-top:11px;padding-right:18px;color:#fff;text-shadow:0 0 2px #410800;font-size:14px;letter-spacing:-1px;}
+#nav-points .nav strong{font-family:'helveticaneuebold'}
+#nav-points .nav .points{font-family:'helveticaneuelight'}
+#nav-points .first{color:#ff6900;padding-right:16px}
+#content{padding:0 26px}
+#content-sidebar{float:left;width:230px;padding-top:60px;}
+#content-sidebar .link1{font-family:'helveticaneuebold';color:#f55e00;font-size:21px;margin-bottom:7px;text-decoration:none;display:block}
+#content-main{margin-left:246px;padding-top:50px}
+.boxes-relutas{position:relative;z-index:2}
+.btn-add-new-item,.btn-click-to-match{display:block;position:absolute;z-index:5}
+.btn-add-new-item{z-index:3;width:150px;height:47px;left:261px;top:103px;background:url("../images/site/btn-add-new-item.png") no-repeat 0 0}
+.btn-click-to-match{z-index:3;width:188px;height:95px;left:243px;top:193px;background:url("../images/site/btn-click-to-match.png") no-repeat 0 0}
+.box-game{position:relative;padding-top:12px;width:274px;float:left;z-index:1;}
+.box-game.first{margin-right:116px}
+.box-drop{position:absolute;left:64px;top:-13px;z-index:2}
+.boxdrop-tit{width:148px;height:41px;background-image:url("../images/site/box-users.png");background-position}
+.boxdrop-tit.usert{background-position:0 0}
+.boxdrop-tit.userw{background-position:0 -41px}
+.boxdrop-list{width:139px;margin-left:5px}
+.boxdrop-list-cont{background:url("../images/site/bg-trans2.png") repeat}
+.listfoot{backgroundwidth:139px;background:url("../images/site/bgfoot.png") no-repeat;height:7px}
+.box-options{width:282px;height:457px;background:url("../images/site/bg-boxscroll.png") no-repeat 0 0;position:relative}
+.bg-shadow{position:absolute;width:274px;height:457px;left:4px;top:0;background:url("../images/site/bg-shadow.png") no-repeat 0 0}
+.boxscroll{height:457px;overflow:scroll;overflow-x:hidden}
+.imgscroll{text-align:center;background:url("../images/site/bg-line1.gif") no-repeat center bottom;padding-bottom:3px}
+.droplist{padding:8px 5px 2px}
+.dropli{list-style:none;color:#fff;font-family:'helveticaneuebold';font-weight:bold;font-size:14px;display:block;padding:0;line-height:13px;cursor:pointer;margin-bottom:2px;letter-spacing:-1px;}
+.dropli span{display:block;padding:3px 3px 3px 18px}
+.dropli:hover{background:url("../images/site/bg-trans3.png") repeat}
+.dropli.active{background:url("../images/site/bg-trans3.png") repeat;}
+.dropli.active span{background:url("../images/site/bg-point.png") no-repeat 5px 6px}

frontend/static/css/site.main.styl

+
+//-------------------------------------------
+// Globales
+//-------------------------------------------
+body
+  background #FFE8C9 url(../images/site/bgBody.jpg) repeat-x 0 0
+
+#wrap
+  margin 0 auto
+  width 1000px
+  height 700px
+  position relative
+  zoom 1
+//-------------------------------------------
+// boxone
+//-------------------------------------------
+.box-1
+  background transparent url(../images/site/box-1.jpg) no-repeat 0 0
+
+.box-one
+  .box-content,
+  .box-inner,
+  &
+    @extend .box-1
+
+  background-position 0 0
+  padding-top 9px
+  width 207px
+
+  .box-content
+    background-position -207px 100% 
+    padding-bottom 13px
+
+  .box-inner
+    background-position -414px 0
+    background-repeat repeat-y
+    padding 1px 22px
+    width (207 - 44)px
+
+  .title
+    margin 0 0 7px
+    color #646E72
+    font-family helvetica
+    font-size 20px
+
+//-------------------------------------------
+// Header
+//-------------------------------------------
+#header
+  position relative
+  height 144px
+
+#logo
+  position absolute
+  top 35px
+  left 33px
+
+#user_tools
+  position absolute
+  top 0
+  right 63px
+
+  .tool