def post(self, *args, **kwargs): """Ensures the user is logged in and rate-limits requests if self.is_rate_limited() is truthy. Then calls self.handle_action() to execute the requested action. """ # ensure the user is logged in (UI shouldn't let tags/favorites/flags be set w/o being logged in) sess = is_logged_in() if not sess: #return self.do_output('error-login-required') #TODO: TMP!! uid = 'fakeuid' else: uid = sess['my_id'] # rate limit actions to guard against bots / malicious users if self.is_rate_limited(): rl = RL.rate_limit(uid) else: rl = RL_HANDLE_NORMALLY # not rate limited if rl == RL_DROP: logging.warn("RL_DROP: %s attempt by %s" % (self.get_action_name(), uid)) self.do_output('captcha-show') return # drop this request elif rl == RL_HANDLE_BUT_SEND_CAPTCHA: logging.info("RL_HANDLE_BUT_SEND_CAPTCHA: %s attempt by %s" % (self.get_action_name(), uid)) self.do_output('captcha-show') else: # empty response means the action was processed self.do_output('') # perform the action self.handle_action(uid, *args, **kwargs)
def post(self): session = is_logged_in(self) if not session: return req = self.request errors = {} dn = validate_string(req, errors, 'dname', 'display name', 100) email = validate_string(req, errors, 'email', 'email', 100) if len(errors): return self.redirect_to_self(errors) uid = session['my_id'] user = User.get_by_key_name(uid) if user.display_name!=dn or user.email!=email: str_update = "dn=%s email=%s ==> dn=%s email=%s" % (user.display_name, user.email, dn, email) user.display_name = dn user.email = email try: user.put() except Exception, e: logging.info("Unable to update user profile: " + str_update) return self.redirect_to_self({'err':'Unable to update your profile. Please try again later'}) # profile has been updated session['my_dname'] = dn session['my_email'] = email logging.info("Updated user profile: " + str_update) memcache.delete('u+c%s' % uid) # clear saved user_info self.redirect('/profile/update?info=Your%20profile%20has%20been%20updated.')
def post(self, *args, **kwargs): """Ensures the user is logged in and rate-limits requests if self.is_rate_limited() is truthy. Then calls self.handle_action() to execute the requested action. """ # ensure the user is logged in (UI shouldn't let tags/favorites/flags be set w/o being logged in) sess = is_logged_in() if not sess: # return self.do_output('error-login-required') # TODO: TMP!! uid = "fakeuid" else: uid = sess["my_id"] # rate limit actions to guard against bots / malicious users if self.is_rate_limited(): rl = RL.rate_limit(uid) else: rl = RL_HANDLE_NORMALLY # not rate limited if rl == RL_DROP: logging.warn("RL_DROP: %s attempt by %s" % (self.get_action_name(), uid)) self.do_output("captcha-show") return # drop this request elif rl == RL_HANDLE_BUT_SEND_CAPTCHA: logging.info("RL_HANDLE_BUT_SEND_CAPTCHA: %s attempt by %s" % (self.get_action_name(), uid)) self.do_output("captcha-show") else: # empty response means the action was processed self.do_output("") # perform the action self.handle_action(uid, *args, **kwargs)
def get(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) feed_key_name = self.request.get('f') if not feed_key_name: return self.redirect('/tracker') # remove the feed from this user's record user = User.get_by_key_name(session['my_id']) n = len(user.feeds) for i in xrange(len(user.feeds)): if user.feeds[i] == feed_key_name: user.feed_names = user.feed_names[:i-1] + user.feed_names[i+1:] user.feeds = user.feeds[:i-1] + user.feeds[i+1:] break user.put() if n > len(user.feeds): self.redirect('/tracker?info=Success', 30*60) # clear the memcache entry for this users' feeds mckey = "user-feeds:%s" % session['my_id'] memcache.delete(mckey) else: self.redirect('/tracker?info=The%20feed%20you%20asked%20to%20stop%20tracking%20was%20not%20being%20tracked.')
def get(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) self.response.headers['Content-Type'] = 'text/html' self.response.out.write(MakoLoader.render('search_new.html', request=self.request))
def get_feed_infos(handler): """Returns an array of 2-tuples (feed_name, feed_key) for the current user, or False on failure. """ session = is_logged_in(handler) if not session: return False uid = session['my_id'] mckey = "user-feeds:%s" % uid feed_infos = memcache.get(mckey) if not feed_infos: user = User.get_by_key_name(uid) if not user: logging.error('cannot find the profile for a logged in user (%s)' % uid) session.terminate() return False feed_keys = [db.Key.from_path('Feed', f) for f in user.feeds] if feed_keys: feeds = db.get(feed_keys) else: feeds = [] feed_infos = zip(user.feed_names, feeds) memcache.set(mckey, feed_infos, 30*60) return feed_infos
def get_feed_infos(handler): """Returns an array of 2-tuples (feed_name, feed_key) for the current user, or False on failure. """ session = is_logged_in(handler) if not session: return False uid = session['my_id'] mckey = "user-feeds:%s" % uid feed_infos = memcache.get(mckey) if not feed_infos: user = User.get_by_key_name(uid) if not user: logging.error('cannot find the profile for a logged in user (%s)' % uid) session.terminate() return False feed_keys = [db.Key.from_path('Feed', f) for f in user.feeds] if feed_keys: feeds = db.get(feed_keys) else: feeds = [] feed_infos = zip(user.feed_names, feeds) memcache.set(mckey, feed_infos, 30 * 60) return feed_infos
def post(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) req = self.request errors = {} ad_url = validate_string(req, errors, 'ad_url', 'Craigslist Ad URL') if ad_url: if ad_url[:7] != 'http://': ad_url = 'http://' + ad_url m = RE_URL_CHECK.match(ad_url) if not m: errors['ad_url'] = 'This URL does not appear to be a valid craigslist.org webpage.' else: m = RE_ID.match(ad_url) if not m: errors['ad_url'] = 'Could not extract the ID from Ad URL' else: cid = int(m.group(1)) if len(errors): return self.redirect_to_self(GET_PARAMS, errors) # efficiency: get Ad and UserCmt at the same time to_put = [] ad_key = db.Key.from_path('Ad', cid) cmt_key = db.Key.from_path('UserCmt', '%s%s' % (session['my_id'], cid)) ad, cmt = db.get([ad_key, cmt_key]) # download the ad if we don't already have it in our db if not ad: ret = self.fetch_and_parse_page(ad_url) if not ret: errors['ad_url'] = 'Unable to download the webpage' return self.redirect_to_self(GET_PARAMS, errors) title, desc, dt = ret ad = Ad(key=ad_key, feeds=['manual'], title=title, desc=desc, update_dt=dt, url=ad_url) to_put = [ad] elif 'manual' not in ad.feeds: ad.feeds.insert(0, 'manual') to_put = [ad] # create UserCmt if not cmt: cmt = UserCmt(key=cmt_key, feeds=ad.feeds) to_put.append(cmt) elif 'manual' in cmt.feeds: return self.redirect('/tracker?info=You%20are%20already%20manually%20tracking%20that%20ad.') elif cmt.feeds != ad.feeds: cmt.feeds = ad.feeds to_put.append(cmt) # save the new entities if to_put: db.put(to_put) # redirect the user to the feed page self.redirect('/tracker?info=Added%20Ad%20%23' + str(cid) + '%20to%20your%20manually%20specified%20list.')
def get(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) self.response.headers['Content-Type'] = 'text/html' self.response.out.write( MakoLoader.render('search_new.html', request=self.request))
def get(self): session = is_logged_in(self) if not session: return self.response.headers['Content-Type'] = 'text/html' self.response.out.write(MakoLoader.render('userprofile_edit.html', request=self.request, display_name=session['my_dname'], email=session['my_email']))
def post(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) req = self.request errors = {} name = validate_string(req, errors, 'name', 'search name', MAX_FEED_NAME_LEN) if not name: name = '' rss_url = req.get('rss_url') if rss_url: feed_key = parse_rss_url(rss_url) if not feed_key: return self.redirect_to_errors(GET_PARAMS, {'error_rss_url':'''This URL isn't in the expected form. Please <a href="/contact">send it to us</a> if you think this is a bug.'''}) if len(errors): return self.redirect_to_self(GET_PARAMS, errors) else: city = validate_string(req, errors, 'city', 'city/region', max_len=50) category = validate_string(req, errors, 'category', 'category', 3) area = '' # TODO: add area picker if not CATEGORIES.has_key(category): errors['category'] = 'Please choose a category.' query = validate_string(req, errors, 'query', 'search string', 100, required=False) if not query: query = '' title_only = req.get('title_only')=='checked' if title_only: stype = 'T' else: stype = 'A' min_cost = validate_int(req, errors, 'min_cost', 'Minimum Cost', 0, None, False) if not min_cost: min_cost = '' max_cost = validate_int(req, errors, 'max_cost', 'Maximum Cost', 0, None, False) if not max_cost: max_cost = '' num_bedrooms = validate_int(req, errors, 'num_bedrooms', 'Number of bedrooms', 1, 8, False) if not num_bedrooms: num_bedrooms = '' cats = req.get('cats')=='checked' dogs = req.get('dogs')=='checked' pics = req.get('pics')=='checked' if len(errors): return self.redirect_to_self(GET_PARAMS, errors) feed_key = Feed.make_key_name(city, category, area, min_cost, max_cost, num_bedrooms, cats, dogs, pics, [], stype, query) # make sure the feed is in the datastore try: feed = Feed.get_or_insert(key_name=feed_key) except Exception, e: logging.error('Unable to create new Feed (%s): %s' % (feed_key, e)) return self.redirect_to_self(GET_PARAMS, {'err':'The service is temporarily unavailable - please try again later.'})
def get(self): session = is_logged_in(self) if not session: return self.response.headers['Content-Type'] = 'text/html' self.response.out.write( MakoLoader.render('userprofile_edit.html', request=self.request, display_name=session['my_dname'], email=session['my_email']))
def post(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) req = self.request errors = {} new_name = validate_string(req, errors, 'new_name', 'new search name', MAX_FEED_NAME_LEN) if not new_name: new_name = '' if len(errors): return self.redirect_to_self(GET_PARAMS, errors) # update the search name user = User.get_by_key_name(session['my_id']) if not user: logging.error( 'Unable to retrieve user record for a logged in user: %s' % session['my_id']) return self.redirect( '/?err=The service is temporarily unavailable - please try again later.' ) feed_key = self.request.get('f') if feed_key not in user.feeds: return self.redirect( "/tracker&err=You%20can't%20rename%20a%20search%20you%20aren't%20tracking." ) for i in xrange(len(user.feeds)): if user.feeds[i] == feed_key: user.feed_names[i] = new_name break try: user.put() except: logging.error( 'Unable to update user record for logged in user: %s' % session['my_id']) return self.redirect( '/tracker?err=The service is temporarily unavailable - please try again later.' ) # invalidate the memcache entry for this users' feeds if it exists mckey = "user-feeds:%s" % session['my_id'] feed_infos = memcache.delete(mckey) # redirect the user to the feed page self.redirect('/view?t=newest&f=%s' % urllib.quote(feed_key))
def post(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) req = self.request errors = {} new_name = validate_string(req, errors, 'new_name', 'new search name', MAX_FEED_NAME_LEN) if not new_name: new_name = '' if len(errors): return self.redirect_to_self(GET_PARAMS, errors) # update the search name user = User.get_by_key_name(session['my_id']) if not user: logging.error('Unable to retrieve user record for a logged in user: %s' % session['my_id']) return self.redirect('/?err=The service is temporarily unavailable - please try again later.') feed_key = self.request.get('f') if feed_key not in user.feeds: return self.redirect("/tracker&err=You%20can't%20rename%20a%20search%20you%20aren't%20tracking.") for i in xrange(len(user.feeds)): if user.feeds[i] == feed_key: user.feed_names[i] = new_name break try: user.put() except: logging.error('Unable to update user record for logged in user: %s' % session['my_id']) return self.redirect('/tracker?err=The service is temporarily unavailable - please try again later.') # invalidate the memcache entry for this users' feeds if it exists mckey = "user-feeds:%s" % session['my_id'] feed_infos = memcache.delete(mckey) # redirect the user to the feed page self.redirect('/view?t=newest&f=%s' % urllib.quote(feed_key))
def post(self): session = is_logged_in(self) if not session: return req = self.request errors = {} dn = validate_string(req, errors, 'dname', 'display name', 100) email = validate_string(req, errors, 'email', 'email', 100) if len(errors): return self.redirect_to_self(errors) uid = session['my_id'] user = User.get_by_key_name(uid) if user.display_name != dn or user.email != email: str_update = "dn=%s email=%s ==> dn=%s email=%s" % ( user.display_name, user.email, dn, email) user.display_name = dn user.email = email try: user.put() except Exception, e: logging.info("Unable to update user profile: " + str_update) return self.redirect_to_self({ 'err': 'Unable to update your profile. Please try again later' }) # profile has been updated session['my_dname'] = dn session['my_email'] = email logging.info("Updated user profile: " + str_update) memcache.delete('u+c%s' % uid) # clear saved user_info self.redirect( '/profile/update?info=Your%20profile%20has%20been%20updated.')
def post(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) req = self.request errors = {} ad_url = validate_string(req, errors, 'ad_url', 'Craigslist Ad URL') if ad_url: if ad_url[:7] != 'http://': ad_url = 'http://' + ad_url m = RE_URL_CHECK.match(ad_url) if not m: errors[ 'ad_url'] = 'This URL does not appear to be a valid craigslist.org webpage.' else: m = RE_ID.match(ad_url) if not m: errors['ad_url'] = 'Could not extract the ID from Ad URL' else: cid = int(m.group(1)) if len(errors): return self.redirect_to_self(GET_PARAMS, errors) # efficiency: get Ad and UserCmt at the same time to_put = [] ad_key = db.Key.from_path('Ad', cid) cmt_key = db.Key.from_path('UserCmt', '%s%s' % (session['my_id'], cid)) ad, cmt = db.get([ad_key, cmt_key]) # download the ad if we don't already have it in our db if not ad: ret = self.fetch_and_parse_page(ad_url) if not ret: errors['ad_url'] = 'Unable to download the webpage' return self.redirect_to_self(GET_PARAMS, errors) title, desc, dt = ret ad = Ad(key=ad_key, feeds=['manual'], title=title, desc=desc, update_dt=dt, url=ad_url) to_put = [ad] elif 'manual' not in ad.feeds: ad.feeds.insert(0, 'manual') to_put = [ad] # create UserCmt if not cmt: cmt = UserCmt(key=cmt_key, feeds=ad.feeds) to_put.append(cmt) elif 'manual' in cmt.feeds: return self.redirect( '/tracker?info=You%20are%20already%20manually%20tracking%20that%20ad.' ) elif cmt.feeds != ad.feeds: cmt.feeds = ad.feeds to_put.append(cmt) # save the new entities if to_put: db.put(to_put) # redirect the user to the feed page self.redirect('/tracker?info=Added%20Ad%20%23' + str(cid) + '%20to%20your%20manually%20specified%20list.')
def get(self): session = is_logged_in(self) if not session: return self.redirect('/') uid = session['my_id'] now = datetime.datetime.now() feed_key_name = self.request.get('f') t = self.request.get('t') overall_view = (not feed_key_name and t != 'newest') if feed_key_name == 'manual': fhid = 'manual' age = desc = None updating_shortly = False if t == 'hidden': name = "Manually-Added Ads that were Hidden" elif t == 'newest': return self.redirect('/tracker') else: name = "Manually-Added Ads" elif feed_key_name: fhid = Feed.hashed_id_from_pk(feed_key_name) # get the user's name for this feed name = get_search_name(self, feed_key_name) if name is None: return self.redirect('/tracker') # user is no longer tracking this feed elif name is False: return self.redirect('/') # login related error # compute how old the data is feed_dt_updated = dt_feed_last_updated(feed_key_name) if not feed_dt_updated: return self.redirect('/tracker?err=That%20feed%20no%20longer%20exists.') age = str_age(feed_dt_updated, now) td = now - feed_dt_updated updating_shortly = td.days>0 or td.seconds>MAX_AGE_MIN*60 if updating_shortly: age += ' - update in progress' # update the feed if we haven't retrieved the latest ads recently updating = update_feed_if_needed(feed_key_name) if updating is None: return self.redirect('/tracker?err=The%20requested%20feed%20does%20not%20exist.') elif overall_view: age = desc = fhid = None updating_shortly = False if t == 'hidden': name = "All Hidden Ads" else: name = "All Rated/Noted Ads" else: # t=newest and feed=all doesn't make sense together return self.redirect('/tracker') # determine which set of ads to show next = self.request.get('next') if t == 'newest': # show the newest ads (regardless of whether the user has commented on them or not) q = Ad.all().filter('feeds =', fhid).order('-update_dt') if next: q.with_cursor(next) ads = q.fetch(ADS_PER_PAGE) # get user comments on these ads, if any user_ad_keys = [db.Key.from_path('UserCmt', '%s%s' % (uid, a.cid)) for a in ads] user_ad_notes = db.get(user_ad_keys) title_extra = 'Newest Ads' else: # show ads this user has commented on/rated (whether to show hidden ads or not depends on t) hidden = (t == 'hidden') q = UserCmt.all() q.filter('uid =', session['my_id']) if fhid: q.filter('feeds =', fhid) if hidden: q.filter('dt_hidden >', DT_PRESITE).order('-dt_hidden') else: q.filter('dt_hidden =', None).order('-rating') if next: q.with_cursor(next) user_ad_notes = q.fetch(ADS_PER_PAGE) # get the ads associated with these comments ad_keys = [db.Key.from_path('Ad', uan.cid) for uan in user_ad_notes] ads = db.get(ad_keys) if t == 'hidden': title_extra = "Ignored Ads" else: title_extra = "Ads I've Rated" # put the ads and their comments together ad_infos = zip(ads, user_ad_notes) # check that each UserCmt.feeds field is up to date with Ad.feeds (can # only do this when we're searching by Ad, i.e., t=newest) if t == 'newest': # TODO: only mark as outdated if they are inequal EXCEPT 'manual' # TODO: when updating cmt.feeds, don't copy over 'manual' (user-specific) # TODO: reconsider this code ... outdated = [(ad,cmt) for ad, cmt in ad_infos if cmt and ad.feeds!=cmt.feeds] if outdated: # update any out of date comments for ad,cmt in outdated: cmt.feeds = ad.feeds db.put([cmt for ad,cmt in outdated]) # whether there may be more ads more = (len(ads) == ADS_PER_PAGE) if more: more = q.cursor() if not more or more==str(next): more = None # get a description of the search we're viewing if fhid and fhid!='manual': tmp_feed = Feed(key_name=feed_key_name) tmp_feed.extract_values() desc = tmp_feed.desc() if not next: page = 1 else: try: page = int(self.request.get('page', 1)) except ValueError: page = 1; self.response.headers['Content-Type'] = 'text/html' self.response.out.write(MakoLoader.render('search_view.html', request=self.request, ADS_PER_PAGE=ADS_PER_PAGE, ads=ad_infos, more=more, age=age, now=now, search_desc=desc, title_extra=title_extra, page=page, name=name, updating_shortly=updating_shortly, overall_view=overall_view))
def post(self): session = is_logged_in(self) if not session: return self.redirect(REDIR_URL) req = self.request errors = {} name = validate_string(req, errors, 'name', 'search name', MAX_FEED_NAME_LEN) if not name: name = '' rss_url = req.get('rss_url') if rss_url: feed_key = parse_rss_url(rss_url) if not feed_key: return self.redirect_to_errors( GET_PARAMS, { 'error_rss_url': '''This URL isn't in the expected form. Please <a href="/contact">send it to us</a> if you think this is a bug.''' }) if len(errors): return self.redirect_to_self(GET_PARAMS, errors) else: city = validate_string(req, errors, 'city', 'city/region', max_len=50) category = validate_string(req, errors, 'category', 'category', 3) area = '' # TODO: add area picker if not CATEGORIES.has_key(category): errors['category'] = 'Please choose a category.' query = validate_string(req, errors, 'query', 'search string', 100, required=False) if not query: query = '' title_only = req.get('title_only') == 'checked' if title_only: stype = 'T' else: stype = 'A' min_cost = validate_int(req, errors, 'min_cost', 'Minimum Cost', 0, None, False) if not min_cost: min_cost = '' max_cost = validate_int(req, errors, 'max_cost', 'Maximum Cost', 0, None, False) if not max_cost: max_cost = '' num_bedrooms = validate_int(req, errors, 'num_bedrooms', 'Number of bedrooms', 1, 8, False) if not num_bedrooms: num_bedrooms = '' cats = req.get('cats') == 'checked' dogs = req.get('dogs') == 'checked' pics = req.get('pics') == 'checked' if len(errors): return self.redirect_to_self(GET_PARAMS, errors) feed_key = Feed.make_key_name(city, category, area, min_cost, max_cost, num_bedrooms, cats, dogs, pics, [], stype, query) # make sure the feed is in the datastore try: feed = Feed.get_or_insert(key_name=feed_key) except Exception, e: logging.error('Unable to create new Feed (%s): %s' % (feed_key, e)) return self.redirect_to_self( GET_PARAMS, { 'err': 'The service is temporarily unavailable - please try again later.' })