예제 #1
0
파일: admin.py 프로젝트: wangjun/appetsy
    def delete(self, shop_id):

        shop = storage.EtsyShops.get_by_key_name(shop_id)

        def delete_records(item):
            records = item.all(keys_only=True).filter("shop =", shop).fetch(300)
            logging.info("Deleting %d %s" % (len(records), str(item)))
            if records:
                db.delete(records)
            return len(records)

        #we are asked to delete a shop
        deleted = 0

        deleted += delete_records(storage.Events)
        deleted += delete_records(storage.Frontpaged)
        deleted += delete_records(storage.Counters)
        deleted += delete_records(storage.Totals)
        deleted += delete_records(storage.Goods)
        deleted += delete_records(storage.Expenses)
        deleted += delete_records(storage.ShopFans)
        deleted += delete_records(storage.ItemFans)
        deleted += delete_records(storage.EtsyListings)

        logging.info(deleted)
        if deleted == 0:
            db.delete(shop)
            appetsy.invalidate_memcache(namespace = shop_id)
            appetsy.invalidate_memcache("users")

            self.redirect("/admin")


        return deleted
예제 #2
0
파일: cron.py 프로젝트: wangjun/appetsy
    def _mark_sold(self, listing, item = None):
        if listing.state != "sold_out":
            return

        if item is None:
            item = db.Query(storage.Goods).filter("listing =", listing).get()

        if item:
            item.status = "sold"
            item.sold = dt.datetime.now()

            if item.shop.currency == "LVL":
                item.price = round(float(item.listing.price) * 0.55789873, 2) #exchange rate usd -> lvl feb-23-2010
            else:
                item.price = float(item.listing.price)

            item.put()
            storage.Totals.add_income(item.shop,
                                      appetsy.today(item.shop),
                                      item.price)

            self.log("Marked '%s' as sold." % item.name)

        listing.sold_on = dt.datetime.now()

        listing.put()
        appetsy.invalidate_memcache("goods", str(item.shop.id)) #forget UI listings
예제 #3
0
파일: admin.py 프로젝트: wangjun/appetsy
    def get(self):
        """forget all the cached stuff"""
        if self.request.get("everything"):
            memcache.flush_all()
        else:
            for shop in storage.EtsyShops.all():
                appetsy.invalidate_memcache(namespace = str(shop.id))

        self.redirect("/")
예제 #4
0
파일: magic.py 프로젝트: wangjun/appetsy
 def user_check(self):
     users = memcache.get("users")
     for email in users:
         for shop_key in users[email]:
             s = EtsyShops.get(shop_key)
             if not s:
                 u = Users.get_by_key_name(self.user.email)
                 u.shops.remove(shop_key)
                 u.put()
                 appetsy.invalidate_memcache("users")
예제 #5
0
파일: plans.py 프로젝트: wangjun/appetsy
 def update(self):
     plan = storage.Counters.get_or_insert("%s:week_%s_plans" % (self.shop.id, appetsy.monday(self.shop).strftime("%U")),
                                           shop = self.shop,
                                           name = "weeks_plan",
                                           count = 10,
                                           timestamp = dt.datetime.combine(appetsy.monday(self.shop), dt.time()))
     plan.count = int(self.request.get("weeks_plan"))
     plan.put()
     
     memcache.set("week_%s_plans" % appetsy.monday(self.shop).strftime("%U"), plan,
                  namespace = str(self.shop.id))
     appetsy.invalidate_memcache("goods", namespace = str(self.shop.id))
예제 #6
0
파일: admin.py 프로젝트: wangjun/appetsy
    def get(self):
        #new user
        email = self.request.get("email")
        shop_name = self.request.get("shop_name")
        if not email:
            self.response.out.write("Give me email!")
            return

        google_user = users.User(email)
        if not google_user:
            return "bad user"

        user = storage.Users.get_or_insert(email, email = email)

        if shop_name:
            from lib.etsy import Etsy2
            etsy = Etsy2(storage.Params.get_param("etsy_key"))
            user_info = etsy.getUser(shop_name, ["Profile", "Shops"])

            import logging
            logging.info(user_info)

            shop_id = user_info.user_id
            shop = storage.EtsyShops.get_or_insert(str(shop_id),
                                                   id = shop_id,
                                                   shop_name = shop_name)

            shop.shop_name = shop_name
            shop.put()


            # go for etsy user info to set the icon and sold count
            if shop.image_url != user_info.Profile.image_url_75x75:
                self.write("Setting shop icon")
                shop.image_url = user_info.Profile.image_url_75x75
                shop.put()

            if shop.key() not in user.shop_keys:
                self.write("Adding %s to '%s' shop" % (user.email, shop.shop_name))
                user.shop_keys.append(shop.key())

        if self.request.get("greeting"):
            user.greeting = self.request.get("greeting")
        user.put()

        appetsy.invalidate_memcache("users")

        self.redirect("/admin")
예제 #7
0
파일: expenses.py 프로젝트: wangjun/appetsy
    def create(self):
        price = float(self.request.get("price") or 0)
        purchase_date =  dt.datetime.strptime(self.request.get("date"), "%d-%b-%Y").date()
        new_expense = storage.Expenses(
            name = self.request.get("name"),
            purchase_date = purchase_date,
            price = price,
            shop = self.shop
        )
        new_expense.put()

        if price:
            storage.Totals.add_expense(self.shop, purchase_date, price)

        appetsy.invalidate_memcache("expenses", namespace = str(self.shop.id))
        return new_expense.key()
예제 #8
0
파일: goods.py 프로젝트: wangjun/appetsy
    def update(self, id):
        good = storage.Goods.get(id)

        listing = None
        if self.request.get("listing_key"):
            listing = storage.EtsyListings.get(self.request.get("listing_key"))


        status = self.request.get("status")
        price, sale_date = None, None


        if good.listing != listing: #if listing has changed, loose the cache
            if good.listing:
                good.listing.in_goods = False
                db.put(good.listing)
                memcache.delete("listing:%d" % good.listing.id)
            if listing:
                listing.in_goods = True
                db.put(listing)
                memcache.delete("listing:%d" % listing.id)

            memcache.delete("available_listings", namespace = str(self.shop.id))

        if status == "sold":
            sale_date = dt.datetime.strptime(self.request.get("sale_date"),
                                             "%d-%b-%Y").replace(minute=1)
            price = float(self.request.get("price") or 0)

            if good.sold and good.price: #remove previous income
                storage.Totals.add_income(self.shop, good.sold, -good.price)


        good.name = self.request.get("good_name")
        good.created = dt.datetime.strptime(self.request.get("creation_date"), "%d-%b-%Y").date()
        good.status = status
        good.sold = sale_date
        good.price = price
        good.listing = listing
        good.put()

        #add new income
        if good.sold and good.price:
            storage.Totals.add_income(self.shop, good.sold, good.price)

        appetsy.invalidate_memcache("goods", namespace = str(self.shop.id))
        return good.key()
예제 #9
0
파일: cron.py 프로젝트: wangjun/appetsy
    def __update_listing(self, d, e):
        """update database listing d with data of etsy listing e"""
        changes = False

        if d.state != e.state:
            self.log("'%s' state '%s' --> '%s'" % (d.title, d.state, e.state))
            d.state = e.state
            if e.state != "active": #we don't care for edits much as they don't change ranking or anything
                storage.Events(listing = d, shop = d.shop, event = d.state).put()
            changes = True

        if hasattr(e, "title") and d.title != e.title:
            self.log("'%s' title --> '%s'" % (d.title, e.title))
            d.title = e.title
            changes = True

        if hasattr(e, "views") and d.views != int(e.views):
            views = int(e.views) - (d.views or 0)
            self.log("'%s' views +%d" % (d.title, views))
            d.views = int(e.views)
            self.__add_exposure(d, views)
            changes = True

        if  hasattr(e, "ending_tsz") and appetsy.zero_timezone(d.ending) != appetsy.etsy_epoch(e.ending_tsz):
            if not d.ending:
                storage.Events(listing = d,
                       shop = d.shop,
                       event = "posted",
                       created = appetsy.etsy_epoch(e.creation_tsz)).put()
            else:
                self.log("'%s' renewed" % d.title)
                storage.Events(listing = d, shop = d.shop, event = "renewed").put()

            d.ending = appetsy.etsy_epoch(e.ending_tsz)
            changes = True

        if hasattr(e, "price") and d.price != float(e.price):
            self.log("'%s' price %.2f --> %.2f" % (e.title, (d.price or 0.0), float(e.price)))
            d.price = float(e.price)
            changes = True

        if changes:
            memcache.set("listing:%d" % d.id, d) #store our memcache copy for next cron
            appetsy.invalidate_memcache("goods", str(d.shop.id)) #forget UI listings

        return changes
예제 #10
0
파일: expenses.py 프로젝트: wangjun/appetsy
    def update(self, id):
        expense = storage.Expenses.get(id)

        if expense.price:
            storage.Totals.add_expense(self.shop, expense.purchase_date, -expense.price)

    
        purchase_date = dt.datetime.strptime(self.request.get("purchase_date"),
                                             "%d-%b-%Y").date()
        price = float(self.request.get("price") or 0)
        
        expense.name = self.request.get("expense_name")
        expense.purchase_date = dt.datetime.strptime(self.request.get("purchase_date"), "%d-%b-%Y").date()
        expense.price = price
        expense.put()

        storage.Totals.add_expense(self.shop, expense.purchase_date, expense.price)

        appetsy.invalidate_memcache("expenses", namespace = str(self.shop.id))
        return expense.key()
예제 #11
0
파일: goods.py 프로젝트: wangjun/appetsy
    def create(self):
        status = self.request.get("status")
        sale_date, price = None, None
        if status == "sold":
            sale_date = dt.datetime.strptime(self.request.get("sale_date"), "%d-%b-%Y")
            price = float(self.request.get("price") or 0)

        new_good = storage.Goods(
            name = self.request.get("good_name"),
            created = dt.datetime.strptime(self.request.get("creation_date"), "%d-%b-%Y").date(),
            status = self.request.get("status"),
            sold = sale_date,
            price = price,
            shop = self.shop
        )
        new_good.put()

        if price and sale_date:
            storage.Totals.add_income(self.shop, sale_date, price)

        appetsy.invalidate_memcache("goods", namespace = str(self.shop.id))
        return new_good.key()
예제 #12
0
파일: magic.py 프로젝트: wangjun/appetsy
    def listings_to_goods(self):
        shop_id = self.request.get("shop")
        shop = storage.EtsyShops.get_by_key_name(shop_id)
        if not shop:
            self.write("Give me shop")
            return

        goods = storage.Goods.all().filter("shop =", shop) \
                                   .filter("status =", "in_stock") \
                                   .fetch(500)
        db.delete(goods)

        listings = storage.EtsyListings.all().filter("shop =", shop) \
                                             .filter("state =", "active") \
                                             .fetch(500)

        inserts = []
        for i, listing in enumerate(listings):
            inserts.append(
                storage.Goods(
                    name = listing.title,
                    created = (listing.ending - dt.timedelta(days = 130)).date(),
                    status = "in_stock",
                    listing = listing,
                    shop = self.shop,
                )
            )
            listing.in_goods = True
            inserts.append(listing)

            if i % 100 == 0:
                db.put(inserts)
                inserts = []

        db.put(inserts)
        appetsy.invalidate_memcache("goods", namespace = str(shop.id))
예제 #13
0
파일: index.py 프로젝트: wangjun/appetsy
    def fans_today(self):
        today = appetsy.today(self.shop) #- dt.timedelta(days=2)
        if today.date() != memcache.get("today", namespace = str(self.shop.id)):
            appetsy.invalidate_memcache("fans", namespace = str(self.shop.id))

        page = self.request.get("page") or "persons"

        fan_list = memcache.get("fan_list", namespace = str(self.shop.id))

        if not fan_list:  #use cache whenever
            data = {}
            by_fan = {}


            shopfaves = storage.ShopFans.all().filter("shop =", self.shop) \
                                          .filter("favored_on >=", today) \
                                          .fetch(500)
            itemfaves = storage.ItemFans.all().filter("shop =", self.shop) \
                                          .filter("favored_on >=", today) \
                                          .fetch(500)

            data["shopfave_count"] = len(shopfaves)

            for fave in shopfaves:
                fan = dict(user_name = fave.fan.user_name,
                            image_url = fave.fan.image_url,
                            favored_on = fave.favored_on,
                            key = str(fave.fan.key()),
                            count = 0)
                by_fan[fave.fan.user_name] = fan


            data["itemfave_count"] = len(itemfaves)

            by_listing = {}
            for fave in itemfaves:
                listing = dict(title = fave.listing.title,
                               key = str(fave.listing.key()),
                               image_url = fave.listing.image_url,
                               count = 0,
                               favored_on = fave.favored_on)
                by_listing.setdefault(fave.listing.id, listing)
                by_listing[fave.listing.id]["count"] += 1
                by_listing[fave.listing.id]["favored_on"] = min(by_listing[fave.listing.id]["favored_on"],
                                                                fave.favored_on)


                fan = dict(user_name = fave.fan.user_name,
                            image_url = fave.fan.image_url,
                            key = str(fave.fan.key()),
                            favored_on = fave.favored_on,
                            count = 0)

                by_fan.setdefault(fave.fan.user_name, fan)
                by_fan[fave.fan.user_name]["favored_on"] = min (by_fan[fave.fan.user_name]["favored_on"],
                                                                fave.favored_on)
                by_fan[fave.fan.user_name]["count"] += 1

            data["shopfaves"] = sorted(by_fan.values(), key = lambda x: x["favored_on"])
            data["listingfaves"] = sorted(by_listing.values(), key = lambda x: x["favored_on"])


            fan_list = appetsy.get_template("index/fans_today.html").render(**data)
            memcache.set("fan_list", fan_list, namespace = str(self.shop.id))
            memcache.set("today", today.date(), namespace = str(self.shop.id))

        #lame current page hack to avoid breaking the cache
        if page == "persons":
            fan_list = fan_list.replace('<div id="person_box" style="display: none">', '<div id="person_box">')
        else:
            fan_list = fan_list.replace('<div id="item_box" style="display: none">', '<div id="item_box">')

        return fan_list
예제 #14
0
파일: cron.py 프로젝트: wangjun/appetsy
    def get(self):
        if not self.etsy:
            return

        listing_id = self.request.get("listing")

        if not listing_id:
            self.log("no listing - exiting!")
            return

        listing = self.get_listing(listing_id)
        if not listing:
            self.log("Can't find listing with id %s" % listing_id)


        self.log("%s: Getting details for %s (%d known faves)..." % (listing.shop.shop_name,
                                                                     listing.title,
                                                                     listing.faves or 0))

        # get all etsy fans
        etsy_favorers_by_timestamp = {}
        def get_listing_info(offset = 0):
            if offset > 0:
                self.log("%d - %d..." % (offset, offset + 100))

            listing_info = self.etsy.getListing(listing.id, ["Images", "FavoredBy:100:%d" % offset])

            if len(listing_info.FavoredBy) > 0 and len(listing_info.FavoredBy) % 100 == 0:
                listing_info.FavoredBy.extend(get_listing_info(offset + 100).FavoredBy)

            return listing_info

        listing_info = get_listing_info()

        for item in listing_info.FavoredBy:
            etsy_favorers_by_timestamp[appetsy.etsy_epoch(item.creation_tsz)] = item
        etsy_timestamps = set(etsy_favorers_by_timestamp.keys())

        #update fan count for item
        listing.faves = len(etsy_timestamps)
        listing.image_url = listing_info.Images[0].url_75x75
        listing.put()

        db_timestamps = memcache.get("listing:%d_fans" % listing.id)
        if not db_timestamps:
            #get all db fans
            db_favorers_by_timestamp = {}
            item_fans = db.GqlQuery("SELECT * FROM ItemFans WHERE listing = :1", listing).fetch(1000)

            db_timestamps = set([appetsy.zero_timezone(item.favored_on) for item in item_fans])


        # if both sets match - go home
        if len(db_timestamps - etsy_timestamps) + len(etsy_timestamps - db_timestamps) == 0:
            self.log("Same fans")
            pending = memcache.get("items_pending_refresh") or []
            if listing.id in pending:
                pending.remove(listing.id)
                memcache.set("items_pending_refresh", pending)
            return


        #new fans in etsy
        item_fans = []
        for timestamp in (etsy_timestamps - db_timestamps):
            favorer = etsy_favorers_by_timestamp[timestamp]
            fan = self.get_fan(favorer)

            item_fans.append(storage.ItemFans(fan = fan,
                                      listing = listing,
                                      shop = listing.shop,
                                      favored_on = appetsy.etsy_epoch(favorer.creation_tsz)))
            self.log("  New fan: '%s'" % (fan.user_name or fan.key()))
        db.put(item_fans)

        #gone fans
        for timestamp in (db_timestamps - etsy_timestamps):
            # FIXME potentially expensive - this will be replaced by key name
            ex_favorer = storage.ItemFans.all().filter("shop =", listing.shop) \
                                       .filter("listing =", listing) \
                                       .filter("favored_on =", timestamp).get()
            self.log("  Removed fave: '%s'" % ex_favorer.fan.user_name)
            db.delete(ex_favorer)


        pending = memcache.get("items_pending_refresh") or []
        if listing.id in pending:
            pending.remove(listing.id)
            memcache.set("items_pending_refresh", pending)

        #update listing fan cache
        memcache.set("listing:%d_fans" % listing.id, etsy_timestamps)

        appetsy.invalidate_memcache("fans", namespace = str(listing.shop.id))
예제 #15
0
파일: cron.py 프로젝트: wangjun/appetsy
    def get(self):
        if not self.etsy:
            return

        """
            stores most recent hundred and offers to go deeper if there is more
        """
        if self.request.get("rebuild"):
            all_fans = storage.ShopFans.all(keys_only = True)
            for i in range(0, all_fans.count(), 500):
                db.delete(all_fans[i:i+499]);

        page = int(self.request.get("page")) if self.request.get("page") else 0


        if not self.ping():
            return

        shop_id = self.request.get("shop")
        if not shop_id:
            for shop in self.shops:
                taskqueue.add(url='/cron/shop?shop=%d' % shop.id, method = 'get')
            return

        shop = storage.EtsyShops.get_by_key_name(shop_id)
        if not shop:
            self.log("Can't get shop by id %s" % shop_id)
            return


        self.write("<html><body><pre>")
        self.log("%s: Getting shop fans (hundred at a time)\n" % shop.shop_name)


        all_seen = False
        offset = page * 100
        fan_number = offset
        fans_added = 0
        fans = []

        try:
            shop_info = self.etsy.getUser(shop.shop_name, ["FavoredBy:100:%d" % offset])
            fans = shop_info.FavoredBy

            if not fans:
                self.log("No fans!")
                return

            # if we are on first page, let's just check for first fan
            # if we have seen him, we go home
            if page == 0:
                seen_last = db.Query(storage.ShopFans).filter("shop =", shop) \
                                              .filter("favored_on =", appetsy.etsy_epoch(fans[0].creation_tsz)) \
                                              .get()
                if seen_last:
                    self.log("Seen last!")
                    fans_added = -1
                    return


            all_fans = storage.ShopFans.all().filter("shop =", shop) \
                                     .filter("favored_on >=", appetsy.etsy_epoch(fans[-1].creation_tsz)).fetch(1000)

            favored_datetimes = [fan.favored_on.replace(tzinfo=appetsy.UtcTzinfo()) for fan in all_fans]

            fan_nicknames = [fan.fan.user_name for fan in all_fans]

            new_fans = []
            for fan in fans:
                fan_number +=1
                fan.date = appetsy.etsy_epoch(fan.creation_tsz)

                user_name = "secret"
                if hasattr(fan, 'user_id'):
                    user_name = fan.user_id

                if fan.date in favored_datetimes:
                    self.write("%d. Have seen this one %s (%s)" % (fan_number,
                                                                   user_name,
                                                                   fan.date))
                else:
                    fans_added +=1
                    self.log("%d. New fan %s (%s)" % (fan_number,
                                                      user_name,
                                                      fan.date))
                    db_fan = self.get_fan(fan)
                    new_fans.append(storage.ShopFans(shop = shop,
                                       fan = db_fan,
                                       favored_on = fan.date))
            db.put(new_fans)


        except DeadlineExceededError:
            self.log("*** Request timed out!")
        except Timeout:
            self.log("*** Database timed out!")
        else:
            if fans_added == 0:
                self.log("Nothing new in %d-%d range" % (offset, offset+100))
            elif fans_added > 0:
                appetsy.invalidate_memcache("fans", namespace=str(shop.id))
            if fans_added == 100: # all new means there are more
                self.log("There are more - going for next batch")
                taskqueue.add(url='/cron/shop?shop=%d&page=%d' % (shop.id, page+1), method = 'get')
        finally:
            self.write("</pre></body></html>")