<commit_before>#!/usr/bin/env python
"""
    This file contains some data in the form of Python
    objects.  We're not storing stuff in a database yet,
    but don't want to write a lot of duplicate HTML, so
    this is our solution.  These models are passed to
    templates so that the data can be rendered.
"""
import datetime

# A list of instructors, each of which is a Python dictionary.
#
instructors = [
    {
        "name": "Alena Gribskov",
        "bio": """
            Alena is Program Director at YEI, where she leads extracurricular
            programs to recruit, instruct, and support Yale entrepreneurs.
            These programs include YEI's flagship Summer Fellowship as well
            as the YEI Tech Bootcamp and Start Something programs, which she
            co–created. Alena is a former YEI fellow,
            graduate of Yale University, and founder of
            Blind Pig Media, a digital publisher.
        """,
        "url": "http://www.linkedin.com/in/alenagribskov/",
        "avatar": "/static/img/alena.png",
        "links": [
            {
                "fa_icon": "fa-twitter",
                "url": "http://www.twitter.com/yeitweets"
            },
            {
                "fa_icon": "fa-linkedin",
                "url": "http://www.linkedin.com/in/alenagribskov/"
            },
        ]
    },
    {
         "name": "Margaret Lee",
        "bio": """

            Margaret Lee is Venture Creation Program (VCP) Coordinator at YEI, overseeing
            the incubation of early-stage Yale startups throughout the academic year and
            during the summer. Additionally, she supports the Yale entrepreneurial
            community and event programming. Margaret holds a B.A. from Yale University, and
            during her time at Yale, was a marketing intern with YEI, ran an international
            Model U.N. conference, and spent summers working at startups in Denver and London.
        """,
        "url": "http://www.linkedin.com/in/margaretklee",
        "avatar": "https://media.licdn.com/mpr/mpr/wc_200_200/p/1/000/1b9/1bd/08ced1e.jpg",
        "links": [
            {
                "fa_icon": "fa-twitter",
                "url": "http://www.twitter.com/yeitweets"
            },
            {
                "fa_icon": "fa-linkedin",
                "url": "http://www.linkedin.com/in/margaretklee"
            },

],
},
]

# A list of upcoming workshops. Again, each is a dictionary.
#
workshops = [
    {
        "title": "Start Something: Ideation",
        "date": datetime.date(2014, 9, 8),
        "google_docs_form_id": "1zOb70KGf3R6X5vozKzX_Md3ZMQt5D452gHLbQv5hytg",
        "description": """
<<<<<<< HEAD
            6:30-8pm. Interested in entrepreneurship but don't have a startup idea yet?
            Join us for a workshop walking you through the human-centered
            design process to generate compelling, viable business opportunities.
            Space is limited. Register by Sep. 4th by 11:59pm.
=======
            All students and faculty welcome. This class will help students
            prepare for the YEI summer fellowship application. Class is FULL,
            no longer accepting new applications.
            Location:

            Evans Hall, Yale SOM, Room 2230, Tuesday 1/14 5-10pm.
>>>>>>> 8f6e1e8ed9575852f3347de4296c990a26e5e2f7
        """,
        "show": False,
        "disabled": True,
    },
    {
        "title": "Start Something: Lean Startup",
        "date": datetime.date(2014, 9, 12),
        "google_docs_form_id": "1DLGAIrjI8lbRU1xV9rWlakpNpPTE9erZDUqd9irLlY0",
        "description": """
<<<<<<< HEAD
            2-3pm. Have a startup idea and ready to take the first step? Learn the
            tactics modern entrepreneurs use to launch their ventures: the lean
            startup methodology, the basics of customer discovery, and the concept
            of product-market fit.  Space is limited. Register by Sep. 8th at 11:59pm.
=======
            Preference given to students interested in food-related products
            and ventures.  Hosted in collaboration with the

                Yale Sustainable Food Project.
            Applications due by 1/29 before midnight. Location:
            YEI.
>>>>>>> 8f6e1e8ed9575852f3347de4296c990a26e5e2f7
        """,
        "show": False,
        "disabled": True,
    },
        {
        "title": "Start Something: Minimum Viable Products",
        "date": datetime.date(2014, 9, 15),
        "google_docs_form_id": "1DLGAIrjI8lbRU1xV9rWlakpNpPTE9erZDUqd9irLlY0",
        "description": """
            6:30-8pm. Ready to start the building your first product? Come learn what a minimum
            viable product (MVP) is, how to use it, and what the next steps are. Space
            is limited. Register by Sep. 11th at 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },
        {
        "title": "Start Something: Intensive",
        "date": datetime.date(2014, 9, 19),
        "google_docs_form_id": "1oNuBtxXTi9IhAh7QCR6gWs5nJ4AcwKimeMRhndSypq0",
        "description": """
            12-5:30pm. The Start Something intensive is a special, day-long workshop
            on the fundamentals of entrepreneurship, encompassing the topics covered
            in "Ideation," "Lean Startup" and "Minimum Viable Products."  This workshop
            is for students who want a "crash course" in entrepreneurship!  Space is
            limited and by application.  Apply by Sep. 11th at 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },
        {
        "title": "Start Something: Lean Startup",
        "date": datetime.date(2014, 9, 23),
        "google_docs_form_id": "1DLGAIrjI8lbRU1xV9rWlakpNpPTE9erZDUqd9irLlY0",
        "description": """
            6:30-8pm. Have a startup idea and ready to take the first step? Learn the
            tactics modern entrepreneurs use to launch their ventures: the lean
            startup methodology, the basics of customer discovery, and the concept
            of product-market fit.  Space is limited. Register by Sep. 18th at 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },

        {
        "title": "Start Something, Engineering",
        "date": datetime.date(2014, 2, 28),
        "google_docs_form_id": "1oNuBtxXTi9IhAh7QCR6gWs5nJ4AcwKimeMRhndSypq0",
        "description": """
            Preference given to students in engineering and the
            sciences with an interest in new ventures based on primary
            research. Applications due the evening of 2/24 before midnight.
            Location:

            Becton Center, CEID, 2/28 12-5:30pm.
        """,
        "show": False,
        "disabled": True,
    },{
        "title": "Start Something, Engineering",
        "date": datetime.date(2014, 2, 28),
        "google_docs_form_id": "1OvYqhVtJa4e1AUcoZ5hl_YYpwVOKy37vEgH5LlT6Y6k",
        "description": """
            Preference given to students in engineering and the sciences.
            Extra focus on new ventures based on primary research.
            Applications due by 1/8/2013. Location: Yale Engineering CEID.
        """,
        "show": False,
        "disabled": True,
    },
]
<commit_msg>Update fall classes and instructors<commit_after>#!/usr/bin/env python
"""
    This file contains some data in the form of Python
    objects.  We're not storing stuff in a database yet,
    but don't want to write a lot of duplicate HTML, so
    this is our solution.  These models are passed to
    templates so that the data can be rendered.
"""
import datetime

# A list of instructors, each of which is a Python dictionary.
#
instructors = [
    {
        "name": "Alena Gribskov",
        "bio": """
            Alena is Program Director at YEI, where she leads extracurricular
            programs to recruit, instruct, and support Yale entrepreneurs.
            These programs include YEI's flagship Summer Fellowship as well
            as the YEI Tech Bootcamp and Start Something programs, which she
            co–created. Alena is a former YEI fellow,
            graduate of Yale University, and founder of
            Blind Pig Media, a digital publisher.
        """,
        "url": "http://www.linkedin.com/in/alenagribskov/",
        "avatar": "/static/img/alena.png",
        "links": [
            {
                "fa_icon": "fa-twitter",
                "url": "http://www.twitter.com/yeitweets"
            },
            {
                "fa_icon": "fa-linkedin",
                "url": "http://www.linkedin.com/in/alenagribskov/"
            },
        ]
    },
    {
         "name": "Margaret Lee",
        "bio": """

            Margaret Lee is Venture Creation Program (VCP) Coordinator at YEI, overseeing
            the incubation of early-stage Yale startups throughout the academic year and
            during the summer. Additionally, she supports the Yale entrepreneurial
            community and event programming. Margaret holds a B.A. from Yale University, and
            during her time at Yale, was a marketing intern with YEI, ran an international
            Model U.N. conference, and spent summers working at startups in Denver and London.
        """,
        "url": "http://www.linkedin.com/in/margaretklee",
        "avatar": "https://media.licdn.com/mpr/mpr/wc_200_200/p/1/000/1b9/1bd/08ced1e.jpg",
        "links": [
            {
                "fa_icon": "fa-twitter",
                "url": "http://www.twitter.com/yeitweets"
            },
            {
                "fa_icon": "fa-linkedin",
                "url": "http://www.linkedin.com/in/margaretklee"
            },

],
},
]

# A list of upcoming workshops. Again, each is a dictionary.
#
workshops = [
    {
        "title": "Start Something: Ideation",
        "date": datetime.date(2014, 9, 8),
        "google_docs_form_id": "1zOb70KGf3R6X5vozKzX_Md3ZMQt5D452gHLbQv5hytg",
        "description": """
            6:30-8pm. Interested in entrepreneurship but don't have a startup idea yet?
            Join us for a workshop walking you through the human-centered
            design process to generate compelling, viable business opportunities.
            Space is limited. Register by Sep. 4th by 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },
    {
        "title": "Start Something: Lean Startup",
        "date": datetime.date(2014, 9, 12),
        "google_docs_form_id": "1DLGAIrjI8lbRU1xV9rWlakpNpPTE9erZDUqd9irLlY0",
        "description": """
            2-3pm. Have a startup idea and ready to take the first step? Learn the
            tactics modern entrepreneurs use to launch their ventures: the lean
            startup methodology, the basics of customer discovery, and the concept
            of product-market fit.  Space is limited. Register by Sep. 8th at 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },
        {
        "title": "Start Something: Minimum Viable Products",
        "date": datetime.date(2014, 9, 15),
        "google_docs_form_id": "1DLGAIrjI8lbRU1xV9rWlakpNpPTE9erZDUqd9irLlY0",
        "description": """
            6:30-8pm. Ready to start the building your first product? Come learn what a minimum
            viable product (MVP) is, how to use it, and what the next steps are. Space
            is limited. Register by Sep. 11th at 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },
        {
        "title": "Start Something: Intensive",
        "date": datetime.date(2014, 9, 19),
        "google_docs_form_id": "1oNuBtxXTi9IhAh7QCR6gWs5nJ4AcwKimeMRhndSypq0",
        "description": """
            12-5:30pm. The Start Something intensive is a special, day-long workshop
            on the fundamentals of entrepreneurship, encompassing the topics covered
            in "Ideation," "Lean Startup" and "Minimum Viable Products."  This workshop
            is for students who want a "crash course" in entrepreneurship!  Space is
            limited and by application.  Apply by Sep. 11th at 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },
        {
        "title": "Start Something: Lean Startup",
        "date": datetime.date(2014, 9, 23),
        "google_docs_form_id": "1DLGAIrjI8lbRU1xV9rWlakpNpPTE9erZDUqd9irLlY0",
        "description": """
            6:30-8pm. Have a startup idea and ready to take the first step? Learn the
            tactics modern entrepreneurs use to launch their ventures: the lean
            startup methodology, the basics of customer discovery, and the concept
            of product-market fit.  Space is limited. Register by Sep. 18th at 11:59pm.
        """,
        "show": True,
        "disabled": False,
    },

        {
        "title": "Start Something, Engineering",
        "date": datetime.date(2014, 2, 28),
        "google_docs_form_id": "1oNuBtxXTi9IhAh7QCR6gWs5nJ4AcwKimeMRhndSypq0",
        "description": """
            Preference given to students in engineering and the
            sciences with an interest in new ventures based on primary
            research. Applications due by 2/23 before midnight.
            Location: Yale Engineering CEID, 2/28 12-5:30pm.
        """,
        "show": False,
        "disabled": True,
    },{
        "title": "Start Something, Engineering",
        "date": datetime.date(2014, 2, 28),
        "google_docs_form_id": "1OvYqhVtJa4e1AUcoZ5hl_YYpwVOKy37vEgH5LlT6Y6k",
        "description": """
            Preference given to students in engineering and the sciences.
            Extra focus on new ventures based on primary research.
            Applications due by 1/8/2013. Location: Yale Engineering CEID.
        """,
        "show": False,
        "disabled": True,
    },
]
<|endoftext|>


<commit_before># coding: utf-8
import datetime
import logging
from werkzeug.utils import import_string
from flask import session, current_app
from flask.ext.babel import lazy_gettext as _l
from quokka.utils import get_current_user, lazy_str_setting
from quokka.core.templates import render_template
from quokka.core.db import db
from quokka.core.models import Publishable, Ordered, Dated, Content
from quokka.modules.media.models import Image

logger = logging.getLogger()

class BaseProductReference(object):
    def get_title(self):
        return getattr(self, 'title', None)

    def get_description(self):
        return getattr(self, 'description', None)

    def get_unity_value(self):
        return getattr(self, 'unity_value', None)

    def get_weight(self):
        return getattr(self, 'weight', None)

    def get_dimensions(self):
        return getattr(self, 'dimensions', None)

    def get_summary(self):
        summary = getattr(self, 'summary', None)
        if not summary:
            try:
                return self.get_description()[:255]
            except:
                pass
        return summary

    def get_extra_value(self):
        return getattr(self, 'extra_value', None)

    def get_uid(self):
        return str(self.id)

    def set_status(self, *args, **kwargs):
        pass

class BaseProduct(BaseProductReference, Content):
    description = db.StringField(required=True)
    unity_value = db.FloatField()
    weight = db.FloatField()
    dimensions = db.StringField()
    extra_value = db.FloatField()

    meta = {
        'allow_inheritance': True
    }

class Item(Ordered, Dated, db.EmbeddedDocument):
    product = db.ReferenceField(Content)
    reference = db.GenericReferenceField()  # customized product
    """
    Must implement all the BaseProduct methods/ its optional
    if None, "product" will be considered
    """
    uid = db.StringField()
    title = db.StringField(required=True, max_length=255)
    description = db.StringField(required=True)
    link = db.StringField()
    quantity = db.FloatField(default=1)
    unity_value = db.FloatField(required=True)
    total_value = db.FloatField()
    weight = db.FloatField()
    dimensions = db.StringField()
    extra_value = db.FloatField()
    allowed_to_set = db.ListField(db.StringField(), default=['quantity'])
    pipeline = db.ListField(db.StringField(), default=[])

    def set_status(self, status):
        if self.reference and hasattr(self.reference, 'set_status'):
            self.reference.set_status(status)
        if self.product and hasattr(self.product, 'set_status'):
            self.product.set_status(status)

    def get_main_image_url(self, thumb=False, default=None):
        try:
            return self.product.get_main_image_url(thumb, default)
        except:
            return None

    @classmethod
    def normalize(cls, kwargs):
        new = {}
        for k, v in kwargs.items():
            field = cls._fields.get(k)
            if not field:
                continue
            new[k] = field.to_python(v)
        return new

    def __unicode__(self):
        return u"{i.uid} {i.title}".format(i=self)

    def get_uid(self):
        try:
            return self.product.get_uid()
        except:
            return self.uid

    @property
    def unity_plus_extra(self):
        return float(self.unity_value or 0) + float(self.extra_value or 0)

    @property
    def total(self):
        self.clean()
        self.total_value = self.unity_plus_extra * float(self.quantity or 1)
        return self.total_value

    def clean(self):
        mapping = [
            ('title', 'get_title'),
            ('description', 'get_description'),
            ('link', 'get_absolute_url'),
            ('unity_value', 'get_unity_value'),
            ('weight', 'get_weight'),
            ('dimensions', 'get_dimensions'),
            ('extra_value', 'get_extra_value'),
            ('uid', 'get_uid'),
        ]

        references = [self.reference, self.product]

        for ref in references:
            if not ref:
                continue
            for attr, method in mapping:
                current = getattr(self, attr, None)
                if current is not None:
                    continue
                setattr(self, attr, getattr(ref, method, lambda: None)())

class Payment(db.EmbeddedDocument):
    uid = db.StringField()
    payment_system = db.StringField()
    method = db.StringField()
    value = db.FloatField()
    extra_value = db.FloatField()
    date = db.DateTimeField()
    confirmed_at = db.DateTimeField()
    status = db.StringField()

class Processor(Publishable, db.DynamicDocument):
    identifier = db.StringField(max_length=100, unique=True)
    module = db.StringField(max_length=255)
    requires = db.ListField(db.StringField(max_length=255))
    description = db.StringField()
    title = db.StringField()
    image = db.ReferenceField(Image, reverse_delete_rule=db.NULLIFY)
    link = db.StringField(max_length=255)
    config = db.DictField(default=lambda: {})
    pipeline = db.ListField(db.StringField(max_length=255), default=[])

    def import_processor(self):
        return import_string(self.module)

    def get_instance(self, *args, **kwargs):
        if not 'config' in kwargs:
            kwargs['config'] = self.config
        kwargs['_record'] = self
        return self.import_processor()(*args, **kwargs)

    def clean(self, *args, **kwargs):
        for item in (self.requires or []):
            import_string(item)
        super(Processor, self).clean(*args, **kwargs)

    def __unicode__(self):
        return self.identifier

    @classmethod
    def get_instance_by_identifier(cls, identifier, cart=None):
        processor = cls.objects.get(identifier=identifier)
        return processor.get_instance(cart=cart)

    @classmethod
    def get_default_processor(cls):
        default = lazy_str_setting(
            'CART_DEFAULT_PROCESSOR',
            default={
                'module': 'quokka.modules.cart.processors.Dummy',
                'identifier': 'dummy',
                'published': True,
                'title': "Test"
            }
        )

        try:
            return cls.objects.get(identifier=default['identifier'])
        except:
            return cls.objects.create(**default)

    def save(self, *args, **kwargs):
        self.import_processor()
        super(Processor, self).save(*args, **kwargs)

class Cart(Publishable, db.DynamicDocument):
    STATUS = (
        ("pending", _l("Pending")),  # not checked out
        ("checked_out", _l("Checked out")),  # not confirmed (payment)
        ("analysing", _l("Analysing")),  # Analysing payment
        ("confirmed", _l("Confirmed")),  # Payment confirmed
        ("completed", _l("Completed")),  # Payment completed (money released)
        ("refunding", _l("Refunding")),  # Buyer asks refund
        ("refunded", _l("Refunded")),  # Money refunded to buyer
        ("cancelled", _l("Cancelled")),  # Cancelled without processing
        ("abandoned", _l("Abandoned")),  # Long time no update
    )
    reference = db.GenericReferenceField()
    """reference must implement set_status(**kwargs) method
    arguments: status(str), value(float), date, uid(str), msg(str)
    and extra(dict).
    Also reference must implement get_uid() which will return
    the unique identifier for this transaction"""

    belongs_to = db.ReferenceField('User',
                                   default=get_current_user,
                                   reverse_delete_rule=db.NULLIFY)
    items = db.ListField(db.EmbeddedDocumentField(Item))
    payment = db.ListField(db.EmbeddedDocumentField(Payment))
    status = db.StringField(choices=STATUS, default='pending')
    total = db.FloatField(default=0)
    extra_costs = db.DictField(default=lambda: {})
    sender_data = db.DictField(default=lambda: {})
    shipping_data = db.DictField(default=lambda: {})
    shipping_cost = db.FloatField(default=0)
    processor = db.ReferenceField(Processor,
                                  default=Processor.get_default_processor,
                                  reverse_delete_rule=db.NULLIFY)
    reference_code = db.StringField()  # Reference code for filtering
    checkout_code = db.StringField()  # The UID for transaction checkout
    transaction_code = db.StringField()  # The UID for transaction
    requires_login = db.BooleanField(default=True)
    continue_shopping_url = db.StringField(
        default=lambda: current_app.config.get(
            'CART_CONTINUE_SHOPPING_URL', '/'
        )
    )
    pipeline = db.ListField(db.StringField(), default=[])
    log = db.ListField(db.StringField(), default=[])
    config = db.DictField(default=lambda: {})

    def set_status(self, status, save=False):
        """
        THis method will be called by the processor
        which will pass a valid status as in STATUS
        so, this method will dispatch the STATUS to
        all the items and also the 'reference' if set
        """
        if self.status != status:
            self.status = status

        if self.reference and hasattr(self.reference, 'set_status'):
            self.reference.set_status(status)

        for item in self.items:
            item.set_status(status)

        if save:
            self.save()

    def addlog(self, msg, save=True):
        self.log.append(u"{0},{1}".format(datetime.datetime.now(), msg))
        logger.debug(msg)
        save and self.save()

    @property
    def uid(self):
        return self.get_uid()

    def get_uid(self):
        try:
            return self.reference.get_uid() or str(self.id)
        except:
            return str(self.id)

    def __unicode__(self):
        return u"{o.uid} - {o.processor.identifier}".format(o=self)

    def get_extra_costs(self):
        if self.extra_costs:
            return sum(self.extra_costs.values())

    @classmethod
    def get_cart(cls):
        """
        get or create a new cart related to the session
        if there is a current logged in user it will be set
        else it will be set during the checkout.
        """
        session.permanent = current_app.config.get(
            "CART_PERMANENT_SESSION", True)
        try:
            cart = cls.objects.get(
                id=session.get('cart_id'),
                status='pending'
            )
            cart.save()
        except (cls.DoesNotExist, db.ValidationError):
            cart = cls(status="pending")
            cart.save()
            session['cart_id'] = str(cart.id)
            try:
                session.pop('cart_pipeline_index')
                session.pop('cart_pipeline_args')
            except KeyError:
                pass

        return cart

    def assign(self):
        self.belongs_to = self.belongs_to or get_current_user()

    def save(self, *args, **kwargs):
        self.total = sum([item.total for item in self.items])
        self.assign()
        super(Cart, self).save(*args, **kwargs)
        if not self.reference_code:
            self.reference_code = self.get_uid()
            self.save()

    def get_item(self, uid):
        # MongoEngine/mongoengine#503
        return self.items.get(uid=uid)

    def set_item(self, **kwargs):
        if 'product' in kwargs:
            if not isinstance(kwargs['product'], Content):
                try:
                    kwargs['product'] = Content.objects.get(
                        id=kwargs['product'])
                except Content.DoesNotExist:
                    kwargs['product'] = None

        uid = kwargs.get(
            'uid',
            kwargs['product'].get_uid() if kwargs.get('product') else None
        )

        if not uid:
            self.addlog("Cannot add item without an uid %s" % kwargs)
            return

        item = self.get_item(uid)

        kwargs = Item.normalize(kwargs)

        if not item:
            # items should only be added if there is a product (for safety)
            if not kwargs.get('product'):
                self.addlog("there is no product to add item")
                return
            allowed = ['product', 'quantity']
            item = self.items.create(
                **{k: v for k, v in kwargs.items() if k in allowed}
            )
            self.addlog("New item created %s" % item, save=False)
        else:
            # update only allowed attributes
            item = self.items.update(
                {k: v for k, v in kwargs.items() if k in item.allowed_to_set},
                uid=item.uid
            )
            self.addlog("Item updated %s" % item, save=False)

            if int(kwargs.get('quantity', "1")) == 0:
                self.addlog("quantity is 0, removed %s" % kwargs, save=False)
                self.remove_item(**kwargs)

        self.save()
        self.reload()
        return item

    def remove_item(self, **kwargs):
        return self.items.delete(**kwargs)

    def checkout(self, processor=None, *args, **kwargs):
        self.set_processor(processor)
        processor_instance = self.processor.get_instance(self, *args, **kwargs)
        if processor_instance.validate():
            return processor_instance.process()
        else:
            self.addlog("Cart did not validate")
            raise Exception("Cart did not validate")  # todo: specialize this

    def get_items_pipeline(self):
        if not self.items:
            return []

        return reduce(
            lambda x, y: x + y, [item.pipeline for item in self.items]
        )

    def build_pipeline(self):
        items = ['quokka.modules.cart.pipelines:StartPipeline']
        items.extend(current_app.config.get('CART_PIPELINE', []))
        items.extend(self.get_items_pipeline())
        items.extend(self.pipeline)
        items.extend(self.processor and self.processor.pipeline or [])
        return items

    def process_pipeline(self):
        if not self.items:
            return render_template('cart/empty_cart.html',
                                   url=self.continue_shopping_url)

        pipelines = self.build_pipeline()
        index = session.get('cart_pipeline_index', 0)
        Pipeline = import_string(pipelines[index])
        return Pipeline(self, pipelines, index)._preprocess()

    def set_processor(self, processor=None):
        if not self.processor:
            self.processor = Processor.get_default_processor()
            self.save()

        if not processor:
            return

        if isinstance(processor, Processor):
            self.processor = processor
            self.save()
            return

        try:
            self.processor = Processor.objects.get(id=processor)
        except:
            self.processor = Processor.objects.get(identifier=processor)

        self.save()

    def get_available_processors(self):
        return Processor.objects(published=True)
<commit_msg>emit to reference on remove_item<commit_after># coding: utf-8
import datetime
import logging
from werkzeug.utils import import_string
from flask import session, current_app
from flask.ext.babel import lazy_gettext as _l
from quokka.utils import get_current_user, lazy_str_setting
from quokka.core.templates import render_template
from quokka.core.db import db
from quokka.core.models import Publishable, Ordered, Dated, Content
from quokka.modules.media.models import Image

logger = logging.getLogger()

class BaseProductReference(object):
    def get_title(self):
        return getattr(self, 'title', None)

    def get_description(self):
        return getattr(self, 'description', None)

    def get_unity_value(self):
        return getattr(self, 'unity_value', None)

    def get_weight(self):
        return getattr(self, 'weight', None)

    def get_dimensions(self):
        return getattr(self, 'dimensions', None)

    def get_summary(self):
        summary = getattr(self, 'summary', None)
        if not summary:
            try:
                return self.get_description()[:255]
            except:
                pass
        return summary

    def get_extra_value(self):
        return getattr(self, 'extra_value', None)

    def get_uid(self):
        return str(self.id)

    def set_status(self, *args, **kwargs):
        pass

    def remove_item(self, *args, **kwargs):
        pass

class BaseProduct(BaseProductReference, Content):
    description = db.StringField(required=True)
    unity_value = db.FloatField()
    weight = db.FloatField()
    dimensions = db.StringField()
    extra_value = db.FloatField()

    meta = {
        'allow_inheritance': True
    }

class Item(Ordered, Dated, db.EmbeddedDocument):
    product = db.ReferenceField(Content)
    reference = db.GenericReferenceField()  # customized product
    """
    Must implement all the BaseProduct methods/ its optional
    if None, "product" will be considered
    """
    uid = db.StringField()
    title = db.StringField(required=True, max_length=255)
    description = db.StringField(required=True)
    link = db.StringField()
    quantity = db.FloatField(default=1)
    unity_value = db.FloatField(required=True)
    total_value = db.FloatField()
    weight = db.FloatField()
    dimensions = db.StringField()
    extra_value = db.FloatField()
    allowed_to_set = db.ListField(db.StringField(), default=['quantity'])
    pipeline = db.ListField(db.StringField(), default=[])

    def set_status(self, status):
        if self.reference and hasattr(self.reference, 'set_status'):
            self.reference.set_status(status)
        if self.product and hasattr(self.product, 'set_status'):
            self.product.set_status(status)

    def get_main_image_url(self, thumb=False, default=None):
        try:
            return self.product.get_main_image_url(thumb, default)
        except:
            return None

    @classmethod
    def normalize(cls, kwargs):
        new = {}
        for k, v in kwargs.items():
            field = cls._fields.get(k)
            if not field:
                continue
            new[k] = field.to_python(v)
        return new

    def __unicode__(self):
        return u"{i.uid} {i.title}".format(i=self)

    def get_uid(self):
        try:
            return self.product.get_uid()
        except:
            return self.uid

    @property
    def unity_plus_extra(self):
        return float(self.unity_value or 0) + float(self.extra_value or 0)

    @property
    def total(self):
        self.clean()
        self.total_value = self.unity_plus_extra * float(self.quantity or 1)
        return self.total_value

    def clean(self):
        mapping = [
            ('title', 'get_title'),
            ('description', 'get_description'),
            ('link', 'get_absolute_url'),
            ('unity_value', 'get_unity_value'),
            ('weight', 'get_weight'),
            ('dimensions', 'get_dimensions'),
            ('extra_value', 'get_extra_value'),
            ('uid', 'get_uid'),
        ]

        references = [self.reference, self.product]

        for ref in references:
            if not ref:
                continue
            for attr, method in mapping:
                current = getattr(self, attr, None)
                if current is not None:
                    continue
                setattr(self, attr, getattr(ref, method, lambda: None)())

class Payment(db.EmbeddedDocument):
    uid = db.StringField()
    payment_system = db.StringField()
    method = db.StringField()
    value = db.FloatField()
    extra_value = db.FloatField()
    date = db.DateTimeField()
    confirmed_at = db.DateTimeField()
    status = db.StringField()

class Processor(Publishable, db.DynamicDocument):
    identifier = db.StringField(max_length=100, unique=True)
    module = db.StringField(max_length=255)
    requires = db.ListField(db.StringField(max_length=255))
    description = db.StringField()
    title = db.StringField()
    image = db.ReferenceField(Image, reverse_delete_rule=db.NULLIFY)
    link = db.StringField(max_length=255)
    config = db.DictField(default=lambda: {})
    pipeline = db.ListField(db.StringField(max_length=255), default=[])

    def import_processor(self):
        return import_string(self.module)

    def get_instance(self, *args, **kwargs):
        if not 'config' in kwargs:
            kwargs['config'] = self.config
        kwargs['_record'] = self
        return self.import_processor()(*args, **kwargs)

    def clean(self, *args, **kwargs):
        for item in (self.requires or []):
            import_string(item)
        super(Processor, self).clean(*args, **kwargs)

    def __unicode__(self):
        return self.identifier

    @classmethod
    def get_instance_by_identifier(cls, identifier, cart=None):
        processor = cls.objects.get(identifier=identifier)
        return processor.get_instance(cart=cart)

    @classmethod
    def get_default_processor(cls):
        default = lazy_str_setting(
            'CART_DEFAULT_PROCESSOR',
            default={
                'module': 'quokka.modules.cart.processors.Dummy',
                'identifier': 'dummy',
                'published': True,
                'title': "Test"
            }
        )

        try:
            return cls.objects.get(identifier=default['identifier'])
        except:
            return cls.objects.create(**default)

    def save(self, *args, **kwargs):
        self.import_processor()
        super(Processor, self).save(*args, **kwargs)

class Cart(Publishable, db.DynamicDocument):
    STATUS = (
        ("pending", _l("Pending")),  # not checked out
        ("checked_out", _l("Checked out")),  # not confirmed (payment)
        ("analysing", _l("Analysing")),  # Analysing payment
        ("confirmed", _l("Confirmed")),  # Payment confirmed
        ("completed", _l("Completed")),  # Payment completed (money released)
        ("refunding", _l("Refunding")),  # Buyer asks refund
        ("refunded", _l("Refunded")),  # Money refunded to buyer
        ("cancelled", _l("Cancelled")),  # Cancelled without processing
        ("abandoned", _l("Abandoned")),  # Long time no update
    )
    reference = db.GenericReferenceField()
    """reference must implement set_status(**kwargs) method
    arguments: status(str), value(float), date, uid(str), msg(str)
    and extra(dict).
    Also reference must implement get_uid() which will return
    the unique identifier for this transaction"""

    belongs_to = db.ReferenceField('User',
                                   default=get_current_user,
                                   reverse_delete_rule=db.NULLIFY)
    items = db.ListField(db.EmbeddedDocumentField(Item))
    payment = db.ListField(db.EmbeddedDocumentField(Payment))
    status = db.StringField(choices=STATUS, default='pending')
    total = db.FloatField(default=0)
    extra_costs = db.DictField(default=lambda: {})
    sender_data = db.DictField(default=lambda: {})
    shipping_data = db.DictField(default=lambda: {})
    shipping_cost = db.FloatField(default=0)
    processor = db.ReferenceField(Processor,
                                  default=Processor.get_default_processor,
                                  reverse_delete_rule=db.NULLIFY)
    reference_code = db.StringField()  # Reference code for filtering
    checkout_code = db.StringField()  # The UID for transaction checkout
    transaction_code = db.StringField()  # The UID for transaction
    requires_login = db.BooleanField(default=True)
    continue_shopping_url = db.StringField(
        default=lambda: current_app.config.get(
            'CART_CONTINUE_SHOPPING_URL', '/'
        )
    )
    pipeline = db.ListField(db.StringField(), default=[])
    log = db.ListField(db.StringField(), default=[])
    config = db.DictField(default=lambda: {})

    def set_status(self, status, save=False):
        """
        THis method will be called by the processor
        which will pass a valid status as in STATUS
        so, this method will dispatch the STATUS to
        all the items and also the 'reference' if set
        """
        if self.status != status:
            self.status = status

        if self.reference and hasattr(self.reference, 'set_status'):
            self.reference.set_status(status)

        for item in self.items:
            item.set_status(status)

        if save:
            self.save()

    def addlog(self, msg, save=True):
        self.log.append(u"{0},{1}".format(datetime.datetime.now(), msg))
        logger.debug(msg)
        save and self.save()

    @property
    def uid(self):
        return self.get_uid()

    def get_uid(self):
        try:
            return self.reference.get_uid() or str(self.id)
        except:
            return str(self.id)

    def __unicode__(self):
        return u"{o.uid} - {o.processor.identifier}".format(o=self)

    def get_extra_costs(self):
        if self.extra_costs:
            return sum(self.extra_costs.values())

    @classmethod
    def get_cart(cls):
        """
        get or create a new cart related to the session
        if there is a current logged in user it will be set
        else it will be set during the checkout.
        """
        session.permanent = current_app.config.get(
            "CART_PERMANENT_SESSION", True)
        try:
            cart = cls.objects.get(
                id=session.get('cart_id'),
                status='pending'
            )
            cart.save()
        except (cls.DoesNotExist, db.ValidationError):
            cart = cls(status="pending")
            cart.save()
            session['cart_id'] = str(cart.id)
            try:
                session.pop('cart_pipeline_index')
                session.pop('cart_pipeline_args')
            except KeyError:
                pass

        return cart

    def assign(self):
        self.belongs_to = self.belongs_to or get_current_user()

    def save(self, *args, **kwargs):
        self.total = sum([item.total for item in self.items])
        self.assign()
        super(Cart, self).save(*args, **kwargs)
        if not self.reference_code:
            self.reference_code = self.get_uid()
            self.save()

    def get_item(self, uid):
        # MongoEngine/mongoengine#503
        return self.items.get(uid=uid)

    def set_item(self, **kwargs):
        if 'product' in kwargs:
            if not isinstance(kwargs['product'], Content):
                try:
                    kwargs['product'] = Content.objects.get(
                        id=kwargs['product'])
                except Content.DoesNotExist:
                    kwargs['product'] = None

        uid = kwargs.get(
            'uid',
            kwargs['product'].get_uid() if kwargs.get('product') else None
        )

        if not uid:
            self.addlog("Cannot add item without an uid %s" % kwargs)
            return

        item = self.get_item(uid)

        kwargs = Item.normalize(kwargs)

        if not item:
            # items should only be added if there is a product (for safety)
            if not kwargs.get('product'):
                self.addlog("there is no product to add item")
                return
            allowed = ['product', 'quantity']
            item = self.items.create(
                **{k: v for k, v in kwargs.items() if k in allowed}
            )
            self.addlog("New item created %s" % item, save=False)
        else:
            # update only allowed attributes
            item = self.items.update(
                {k: v for k, v in kwargs.items() if k in item.allowed_to_set},
                uid=item.uid
            )
            self.addlog("Item updated %s" % item, save=False)

            if int(kwargs.get('quantity', "1")) == 0:
                self.addlog("quantity is 0, removed %s" % kwargs, save=False)
                self.remove_item(**kwargs)

        self.save()
        self.reload()
        return item

    def remove_item(self, **kwargs):
        deleted = self.items.delete(**kwargs)
        print self.reference
        if self.reference and hasattr(self.reference, 'remove_item'):
            self.reference.remove_item(**kwargs)
            print self.reference
        return deleted

    def checkout(self, processor=None, *args, **kwargs):
        self.set_processor(processor)
        processor_instance = self.processor.get_instance(self, *args, **kwargs)
        if processor_instance.validate():
            return processor_instance.process()
        else:
            self.addlog("Cart did not validate")
            raise Exception("Cart did not validate")  # todo: specialize this

    def get_items_pipeline(self):
        if not self.items:
            return []

        return reduce(
            lambda x, y: x + y, [item.pipeline for item in self.items]
        )

    def build_pipeline(self):
        items = ['quokka.modules.cart.pipelines:StartPipeline']
        items.extend(current_app.config.get('CART_PIPELINE', []))
        items.extend(self.get_items_pipeline())
        items.extend(self.pipeline)
        items.extend(self.processor and self.processor.pipeline or [])
        return items

    def process_pipeline(self):
        if not self.items:
            return render_template('cart/empty_cart.html',
                                   url=self.continue_shopping_url)

        pipelines = self.build_pipeline()
        index = session.get('cart_pipeline_index', 0)
        Pipeline = import_string(pipelines[index])
        return Pipeline(self, pipelines, index)._preprocess()

    def set_processor(self, processor=None):
        if not self.processor:
            self.processor = Processor.get_default_processor()
            self.save()

        if not processor:
            return

        if isinstance(processor, Processor):
            self.processor = processor
            self.save()
            return

        try:
            self.processor = Processor.objects.get(id=processor)
        except:
            self.processor = Processor.objects.get(identifier=processor)

        self.save()

    def get_available_processors(self):
        return Processor.objects(published=True)
<|endoftext|>


<commit_before>from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# Create models
class Houses(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(10), unique=True, nullable=False)
    desc = db.Column(db.String(1000))
    shortdesc = db.Column(db.String(140))
    captain = db.Column(db.String(100))
    color = db.Column(db.String(6))
    imagepath = db.Column(db.String(128))

    def __str__(self):
        return self.name

class Markers(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(10), unique=True, nullable=False)
    point_value = db.Column(db.Integer, nullable=False)
    house_id = db.Column(db.Integer, db.ForeignKey(Houses.id), nullable=True)
    in_current_use = db.Column(db.Boolean, default=True)
    is_hidden = db.Column(db.Boolean)
    batch = db.Column(db.String(20))
    location = db.Column(db.String(15))
    houses = db.relationship('Houses', backref=db.backref('Markers'))

    def __str__(self):
        return self.name

class Users(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    uname = db.Column(db.String(30), unique=True, nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    pwhash = db.Column(db.Binary(60), nullable=False)
    house_id = db.Column(db.Integer, db.ForeignKey(Houses.id), nullable=False)
    points = db.Column(db.Integer)
    houses = db.relationship('Houses', backref=db.backref('Users'))

    def __str__(self):
        return self.uname

class Scans(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey(Users.id), nullable=False)
    marker_id = db.Column(db.Integer, db.ForeignKey(Markers.id), nullable=False)
    point_value = db.Column(db.Integer, nullable=False)
    scan_time = db.Column(db.DateTime)
    users = db.relationship('Users', backref=db.backref('Scans'))
    markers = db.relationship('Markers', backref=db.backref('Scans'))

    def __str__(self):
        return  self.users.uname + " scanned '" + self.markers.name + "'"

class Pages(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), unique=True, nullable=False)
    route = db.Column(db.String(15), unique=True, nullable=False)
    content = db.Column(db.String(5000), nullable=False)
    custom_layout = db.Column(db.Boolean, default=False)
    no_wrap = db.Column(db.Boolean, default=False)

    def __str__(self):
        return  self.title
<commit_msg>Changed models for markers and Pages to reflect db<commit_after>from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# Create models
class Houses(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(10), unique=True, nullable=False)
    desc = db.Column(db.String(1000))
    shortdesc = db.Column(db.String(140))
    captain = db.Column(db.String(100))
    color = db.Column(db.String(6))
    imagepath = db.Column(db.String(128))

    def __str__(self):
        return self.name

class Markers(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True, nullable=False)
    point_value = db.Column(db.Integer, nullable=False)
    house_id = db.Column(db.Integer, db.ForeignKey(Houses.id), nullable=True)
    in_current_use = db.Column(db.Boolean, default=True)
    is_hidden = db.Column(db.Boolean)
    batch = db.Column(db.String(20))
    location = db.Column(db.String(15))
    houses = db.relationship('Houses', backref=db.backref('Markers'))

    def __str__(self):
        return self.name

class Users(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    uname = db.Column(db.String(30), unique=True, nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    pwhash = db.Column(db.Binary(60), nullable=False)
    house_id = db.Column(db.Integer, db.ForeignKey(Houses.id), nullable=False)
    points = db.Column(db.Integer)
    houses = db.relationship('Houses', backref=db.backref('Users'))

    def __str__(self):
        return self.uname

class Scans(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey(Users.id), nullable=False)
    marker_id = db.Column(db.Integer, db.ForeignKey(Markers.id), nullable=False)
    point_value = db.Column(db.Integer, nullable=False)
    scan_time = db.Column(db.DateTime)
    users = db.relationship('Users', backref=db.backref('Scans'))
    markers = db.relationship('Markers', backref=db.backref('Scans'))

    def __str__(self):
        return  self.users.uname + " scanned '" + self.markers.name + "'"

class Pages(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), unique=True, nullable=False)
    route = db.Column(db.String(15), unique=True, nullable=False)
    content = db.Column(db.String(12000), nullable=False)
    custom_layout = db.Column(db.Boolean, default=False)
    no_wrap = db.Column(db.Boolean, default=False)

    def __str__(self):
        return  self.title
<|endoftext|>


<commit_before># coding=utf-8
# import os
# import sys

# We do this to ensure that our module-internal imports work
# sys.path.append(os.path.dirname(os.path.realpath(__file__)))

__author__ = "Gareth Coles"
<commit_msg>Begin argument parsing work<commit_after># coding=utf-8
import argparse

"""
Ultros - Module runnable
"""

__author__ = "Gareth Coles"
__version__ = "0.0.1"

def start():
    pass

def init():
    pass

if __name__ == "__main__":
    parser = argparse.ArgumentParser(prog="ultros")

    parser.add_argument(
        "--version", action="version", version=f"Ultros {__version__}"
    )

    parser.add_argument(
        "--config", help="specify a directory containing configuration files",
        default="./config"
    )
    parser.add_argument(
        "--data", help="specify a directory to store data files",
        default="./data"
    )

    subparsers = parser.add_subparsers()

    parser_init = subparsers.add_parser(
        "init", help="Create a default directory structure with example files"
    )
    parser_init.set_defaults(func=init)

    parser_start = subparsers.add_parser("start", help="Start Ultros")
    parser_start.set_defaults(func=start)

    args = parser.parse_args()

    if hasattr(args, "func"):
        args.func(args)
    else:
        print(parser.format_usage())
<|endoftext|>


<commit_before>from google.appengine.ext import db
from google.appengine.ext import blobstore
from google.appengine.api import memcache
from google.appengine.api import images
from google.appengine.api import search
from google.appengine.api import mail
from settings import JINJA_ENVIRONMENT
import datetime
import json
import operator

class User(db.Model):
    subscriptions = db.ListProperty(db.Key)
    email = db.EmailProperty()
    google_id = db.StringProperty()

    @staticmethod
    def create_new_user(email, google_id):
        user = User.gql("WHERE google_id = :1", google_id).get()
        if user:
            return user, False # no new user is created.
        else:
            user = User(email=db.Email(email), google_id=google_id).put()
            return user, True # new  user created

    @staticmethod
    def get_user(google_id):
        return User.gql("WHERE google_id = :1", google_id).get()

    def subscribe(self, stream):
        self.subscriptions.append(stream.key())
        self.put()

    def unsubscribe(self, stream):
        if stream.key() in self.subscriptions:
            self.subscriptions.remove(stream.key())
        self.put()

class Stream(db.Model):
    owner = db.ReferenceProperty(User,
                                 required=True,
                                 collection_name="owned")
    name = db.StringProperty()
    updated_at = db.DateTimeProperty(auto_now=True)
    created_at = db.DateTimeProperty(auto_now_add=True)
    cover_image = db.StringProperty()
    tags = db.StringListProperty()
    view_count = db.IntegerProperty(default=0)

    def __dict__(self):
        return {
                "id" : self.key().id(),
                "name" : self.name,
                "created_at"  : self.created_at.strftime("%d/%m/%y"),
                "updated_at" : self.updated_at.strftime("%d/%m/%y"),
                "cover_image" : self.cover_image,
                "tags" : self.tags,
                "view_count" : str(self.view_count),
                "count" : self.images.count()
                }

    # cursor can be used: https://developers.google.com/appengine/docs/python/datastore/queries#Python_Limitations_of_cursors
    def get_images(self, limit=None, useCursor=False, user=None, resetCursor=False):
        # override use cursor flag if resetCursor flag is set
        useCursor = useCursor and (not resetCursor)

        if resetCursor:
            memcache.delete("stream_images:cursor:%s")

        stream_photos_query  = self.images
        if useCursor:
            cursor = memcache.get("stream_images:cursor:%s" % user.google_id)

        if useCursor and cursor:
            stream_photos_query.with_cursor(start_cursor=cursor)

        stream_photos = stream_photos_query.fetch(limit=limit)

        cursor = stream_photos_query.cursor()
        memcache.set("stream_images:cursor:%s" % user.google_id, cursor)

        return stream_photos

    def to_json(self):
        return json.dumps(self.__dict__())

    def update_view_count(self):
        self.view_count = int(self.view_count) + 1
        self.put()
        View(stream=self).put()
        return self.view_count

    @staticmethod
    def create_user_stream(name, user, cover_image, tags):
        stream = Stream.gql("WHERE name = '%s'" % name).get()
        sane_tags = [t.strip() for t in tags.split(',')]
        if not stream:
            stream = Stream(owner=user,
                        name = name,
                        cover_image = cover_image,
                        tags = sane_tags, view_count=0)
            stream.put()
        else:
            return None, "Stream already present"
        return stream, "New Stream Created"

    def add_photo(self, img, title, comments):
        photo = Photo(full_size_image=img,
                    title=title,
                    comments=comments,
                    stream=self)
        photo.put()
        return photo

    @staticmethod
    def get_all_owned_streams(user):
        owned_streams = user.owned.fetch(limit=None)
        user_streams = []
        for stream in owned_streams:
            user_streams.append(stream.__dict__())

        return user_streams

    @staticmethod
    def get_all_subscribed_streams(user):
        streams = user.subscriptions
        subscribed_streams = []
        for stream in streams:
            stream_obj = db.get(stream)
            if stream_obj:
                subscribed_streams.append(db.get(stream).__dict__())

        return subscribed_streams

class Search():
    @staticmethod
    def find_by_keyword(keyword):
        all_stream = Stream.all()
        results = []
        for stream in all_stream:
            if (keyword.strip() in stream.name) or (keyword.strip() in ' '.join(stream.tags)):
                results.append(stream.__dict__())
        return results
"""
PHOTO
"""
class Photo(db.Model):
    comments = db.StringProperty("comments")
    title = db.StringProperty("title")
    stream = db.ReferenceProperty(Stream, collection_name="images")
    blob_key = blobstore.BlobReferenceProperty()

    def __dict__(self, resize=None):
        if resize:
            url = images.get_serving_url(self.blob_key) + ('=s%s' % resize)
        return {
                "id" : self.key().id(),
                "url" : images.get_serving_url(self.blob_key),
                "comments" : self.comments,
                "stream_id" : self.stream.key().id()
                }

class View(db.Model):
    stream = db.ReferenceProperty(Stream, collection_name="views")
    created_at = db.DateTimeProperty(auto_now_add=True)

    @staticmethod
    def seconds_ago(time_s):
        return datetime.datetime.now() - datetime.timedelta(seconds=time_s)

    @staticmethod
    def getTop():
        stream_count = {}
        views = View.all().filter('created_at >', View.seconds_ago(2*60*60))
        for view in views:
            if view.stream and (view.stream.key().id() in stream_count):
                stream_count[view.stream.key().id()] += 1
            else:
                stream_count[view.stream.key().id()] = 1
        return sorted(stream_count.items(), key=operator.itemgetter(1), reverse=True)[0:3]

class TrendSetter(db.Model):
    @staticmethod
    def topTrending():
        TrendSetter.setTrend()
        result = {}
        stream_dict = dict(memcache.get("top_trending") or {})
        i = 0
        for streamid in stream_dict:
            stream = Stream.get_by_id(streamid)
            if stream:
                result[i]= { "stream" : stream.__dict__(), "one_hour_view_count" : stream_dict[streamid] }
                i += 1

        return dict(sorted(result.items(), key=lambda x: x[1]["one_hour_view_count"], reverse=True))

    @staticmethod
    def setTrend():
        if len(View.getTop()) > 0:
            memcache.set("top_trending", View.getTop())

class Jobs(db.Model):
    job_type = db.StringProperty("job_type")
    duration = db.StringProperty("duration")
    user = db.ReferenceProperty(User, collection_name="jobs")

    @staticmethod
    def getJobs(duration, job_type):
        job_q = Jobs.gql("WHERE job_type = :1 and duration = :2", job_type, duration)
        return job_q.fetch(limit=None)

    @staticmethod
    def createOrUpdate(job_type, duration, user):
        req_type = None
        if user.jobs:
            req_type = [job for job in user.jobs if job.job_type == job_type]

        if req_type:
            req_type[0].duration = duration;
            req_type[0].put()
        else:
            Jobs(user=user, job_type=job_type, duration=duration).put()

class CronHandler(db.Model):
    @staticmethod
    def initialize():
        pass

    @staticmethod
    def runJob(duration):
        jobs = Jobs.getJobs(duration, "trends")
        emails = [job.user.email for job in jobs]
        Mailer.sendMail(emails, "trends")

    @staticmethod
    def hourlyJobs():
        pass

class Mailer():
    @staticmethod
    def sendMail(ids, mailType):
        message = mail.EmailMessage(sender="ankit3goyal@gmail.com",
                            subject="Hi! from imgshare!")

        template = JINJA_ENVIRONMENT.get_template('templates/newsletter.html')

        for email in ids:
            message.to = email
            message.html = template.render(Mailer.trendingEmailTemplateValues())
            message.send()
        return

    @staticmethod
    def trendingEmailTemplateValues():
        template_values = {}
        streams = TrendSetter.topTrending()
        template_values['streams'] = streams
        return template_values

<commit_msg>making search better<commit_after>from google.appengine.ext import db
from google.appengine.ext import blobstore
from google.appengine.api import memcache
from google.appengine.api import images
from google.appengine.api import search
from google.appengine.api import mail
from settings import JINJA_ENVIRONMENT
import datetime
import json
import operator

class User(db.Model):
    subscriptions = db.ListProperty(db.Key)
    email = db.EmailProperty()
    google_id = db.StringProperty()

    @staticmethod
    def create_new_user(email, google_id):
        user = User.gql("WHERE google_id = :1", google_id).get()
        if user:
            return user, False # no new user is created.
        else:
            user = User(email=db.Email(email), google_id=google_id).put()
            return user, True # new  user created

    @staticmethod
    def get_user(google_id):
        return User.gql("WHERE google_id = :1", google_id).get()

    def subscribe(self, stream):
        self.subscriptions.append(stream.key())
        self.put()

    def unsubscribe(self, stream):
        if stream.key() in self.subscriptions:
            self.subscriptions.remove(stream.key())
        self.put()

class Stream(db.Model):
    owner = db.ReferenceProperty(User,
                                 required=True,
                                 collection_name="owned")
    name = db.StringProperty()
    updated_at = db.DateTimeProperty(auto_now=True)
    created_at = db.DateTimeProperty(auto_now_add=True)
    cover_image = db.StringProperty()
    tags = db.StringListProperty()
    view_count = db.IntegerProperty(default=0)

    def __dict__(self):
        return {
                "id" : self.key().id(),
                "name" : self.name,
                "created_at"  : self.created_at.strftime("%d/%m/%y"),
                "updated_at" : self.updated_at.strftime("%d/%m/%y"),
                "cover_image" : self.cover_image,
                "tags" : self.tags,
                "view_count" : str(self.view_count),
                "count" : self.images.count()
                }

    # cursor can be used: https://developers.google.com/appengine/docs/python/datastore/queries#Python_Limitations_of_cursors
    def get_images(self, limit=None, useCursor=False, user=None, resetCursor=False):
        # override use cursor flag if resetCursor flag is set
        useCursor = useCursor and (not resetCursor)

        if resetCursor:
            memcache.delete("stream_images:cursor:%s")

        stream_photos_query  = self.images
        if useCursor:
            cursor = memcache.get("stream_images:cursor:%s" % user.google_id)

        if useCursor and cursor:
            stream_photos_query.with_cursor(start_cursor=cursor)

        stream_photos = stream_photos_query.fetch(limit=limit)

        cursor = stream_photos_query.cursor()
        memcache.set("stream_images:cursor:%s" % user.google_id, cursor)

        return stream_photos

    def to_json(self):
        return json.dumps(self.__dict__())

    def update_view_count(self):
        self.view_count = int(self.view_count) + 1
        self.put()
        View(stream=self).put()
        return self.view_count

    @staticmethod
    def create_user_stream(name, user, cover_image, tags):
        stream = Stream.gql("WHERE name = '%s'" % name).get()
        sane_tags = [t.strip() for t in tags.split(',')]
        if not stream:
            stream = Stream(owner=user,
                        name = name,
                        cover_image = cover_image,
                        tags = sane_tags, view_count=0)
            stream.put()
        else:
            return None, "Stream already present"
        return stream, "New Stream Created"

    def add_photo(self, img, title, comments):
        photo = Photo(full_size_image=img,
                    title=title,
                    comments=comments,
                    stream=self)
        photo.put()
        return photo

    @staticmethod
    def get_all_owned_streams(user):
        owned_streams = user.owned.fetch(limit=None)
        user_streams = []
        for stream in owned_streams:
            user_streams.append(stream.__dict__())

        return user_streams

    @staticmethod
    def get_all_subscribed_streams(user):
        streams = user.subscriptions
        subscribed_streams = []
        for stream in streams:
            stream_obj = db.get(stream)
            if stream_obj:
                subscribed_streams.append(db.get(stream).__dict__())

        return subscribed_streams

class Search():
    @staticmethod
    def find_by_keyword(keyword):
        all_stream = Stream.all()
        results = []
        for stream in all_stream:
            for token in keyword.split(' '):
                if (token.strip().lower() in stream.name.lower() or (token.strip().lower() in ' '.join(stream.tags).lower())):
                    if stream.__dict__() not in results:
                        results.append(stream.__dict__())
        return results
"""
PHOTO
"""
class Photo(db.Model):
    comments = db.StringProperty("comments")
    title = db.StringProperty("title")
    stream = db.ReferenceProperty(Stream, collection_name="images")
    blob_key = blobstore.BlobReferenceProperty()

    def __dict__(self, resize=None):
        if resize:
            url = images.get_serving_url(self.blob_key) + ('=s%s' % resize)
        return {
                "id" : self.key().id(),
                "url" : images.get_serving_url(self.blob_key),
                "comments" : self.comments,
                "stream_id" : self.stream.key().id()
                }

class View(db.Model):
    stream = db.ReferenceProperty(Stream, collection_name="views")
    created_at = db.DateTimeProperty(auto_now_add=True)

    @staticmethod
    def seconds_ago(time_s):
        return datetime.datetime.now() - datetime.timedelta(seconds=time_s)

    @staticmethod
    def getTop():
        stream_count = {}
        views = View.all().filter('created_at >', View.seconds_ago(2*60*60))
        for view in views:
            if view.stream and (view.stream.key().id() in stream_count):
                stream_count[view.stream.key().id()] += 1
            else:
                stream_count[view.stream.key().id()] = 1
        return sorted(stream_count.items(), key=operator.itemgetter(1), reverse=True)[0:3]

class TrendSetter(db.Model):
    @staticmethod
    def topTrending():
        TrendSetter.setTrend()
        result = {}
        stream_dict = dict(memcache.get("top_trending") or {})
        i = 0
        for streamid in stream_dict:
            stream = Stream.get_by_id(streamid)
            if stream:
                result[i]= { "stream" : stream.__dict__(), "one_hour_view_count" : stream_dict[streamid] }
                i += 1

        return dict(sorted(result.items(), key=lambda x: x[1]["one_hour_view_count"], reverse=True))

    @staticmethod
    def setTrend():
        if len(View.getTop()) > 0:
            memcache.set("top_trending", View.getTop())

class Jobs(db.Model):
    job_type = db.StringProperty("job_type")
    duration = db.StringProperty("duration")
    user = db.ReferenceProperty(User, collection_name="jobs")

    @staticmethod
    def getJobs(duration, job_type):
        job_q = Jobs.gql("WHERE job_type = :1 and duration = :2", job_type, duration)
        return job_q.fetch(limit=None)

    @staticmethod
    def createOrUpdate(job_type, duration, user):
        req_type = None
        if user.jobs:
            req_type = [job for job in user.jobs if job.job_type == job_type]

        if req_type:
            req_type[0].duration = duration;
            req_type[0].put()
        else:
            Jobs(user=user, job_type=job_type, duration=duration).put()

class CronHandler(db.Model):
    @staticmethod
    def initialize():
        pass

    @staticmethod
    def runJob(duration):
        jobs = Jobs.getJobs(duration, "trends")
        emails = [job.user.email for job in jobs]
        Mailer.sendMail(emails, "trends")

    @staticmethod
    def hourlyJobs():
        pass

class Mailer():
    @staticmethod
    def sendMail(ids, mailType):
        message = mail.EmailMessage(sender="ankit3goyal@gmail.com",
                            subject="Hi! from imgshare!")

        template = JINJA_ENVIRONMENT.get_template('templates/newsletter.html')

        for email in ids:
            message.to = email
            message.html = template.render(Mailer.trendingEmailTemplateValues())
            message.send()
        return

    @staticmethod
    def trendingEmailTemplateValues():
        template_values = {}
        streams = TrendSetter.topTrending()
        template_values['streams'] = streams
        return template_values

<|endoftext|>


<commit_before>class XMPPModule():
	xmpp = None
	threadfunc = None

	# Initialize the module, start any passive threads here
	def __init__(self, xmpp):
		self.xmpp = xmpp

	# Start the passive thread if one is set
	def start(self):
		pass

	# Stop the passive thread
	def stop(self):
		pass

	# Called when a message is received. Passes in whole message object
	def recvMsg(self, msg):
		pass

	# Called when a group message is received, useful for early separation
	def recvGroupMsg(self, msg):
		pass
<commit_msg>Tweak to module API, handleMessage default moduleler<commit_after>class XMPPModule():
	xmpp = None
	threadfunc = None

	# Initialize the module, start any passive threads here
	def __init__(self, xmpp):
		self.xmpp = xmpp

	# Start the passive thread if one is set
	def start(self):
		pass

	# Stop the passive thread
	def stop(self):
		pass

	# Called when a message is received. Passes in whole message object
	def recvMsg(self, msg):
		self.handleMessage(msg)

	# Called when a group message is received, useful for early separation
	def recvGroupMsg(self, msg):
		self.handleMessage(msg)

	# Default, handle all messages the same
	def handleMessage(self, msg):
		pass
<|endoftext|>