Exemple #1
0
  def _QueryModel(self, search_dict, ancestor=None):
    """Queries the model class for field-value pairs.

    Args:
      search_dict: A dictionary mapping from field name to search by to the
          search term.
      ancestor: ndb.Key, If provided, the ancestor for the query.

    Returns:
      The model query.

    Raises:
      QueryError: If the queried field is not a property of the model.
      QueryTypeError: If search_term does not match the type of the search_base
          model property.
    """
    filter_nodes = []
    for search_base, search_term in search_dict.items():
      field_name = string_utils.CamelToSnakeCase(search_base)

      # If the model class offers a translation function for property queries,
      # invoke it and set the field and search term to the result.
      try:
        field_name, search_term = self.MODEL_CLASS.TranslatePropertyQuery(
            field_name, search_term)
      except AttributeError:
        pass
      else:
        logging.info('Converted query to (%s = %s)', field_name, search_term)

      # Check for the property on the model itself (as opposed to, say, catching
      # a getattr exception) to ensure that the field being accessed is an ndb
      # property as opposed to a Python attribute.
      if not model_utils.HasProperty(self.MODEL_CLASS, field_name):
        raise QueryError('Invalid searchBase %s' % field_name)

      field = getattr(self.MODEL_CLASS, field_name)

      # If the field is of a non-string type, attempt to coerce the argument to
      # conform to this type
      search_term = _CoerceQueryParam(field, search_term)

      filter_nodes.append(ndb.FilterNode(field_name, '=', search_term))

    query = self.MODEL_CLASS.query(ancestor=ancestor)
    if filter_nodes:
      query = query.filter(ndb.AND(*filter_nodes))
    return query
Exemple #2
0
    def dispatch(self):
        # Get a session store for this request.
        self.session_store = sessions.get_store(request=self.request)

        if not self.session.get("email"):
            cookie = self.request.cookies.get('remember_me2')
            if cookie:
                chashed, cemail, key = cookie.split("&")
                result = self.check_password(chashed, cemail)
                if result:
                    query = Users.query(Users.email == cemail)
                    user = query.get()
                    if user:
                        self.set_profile_image(user.key.urlsafe())
                        check_cookie = LoginHistory.query(
                            ndb.AND(LoginHistory.user_id == user.key.urlsafe(),
                                    LoginHistory.cookie_key == key),
                            ancestor=HISTORY_PARENT_KEY).get()
                        if check_cookie:
                            self.session['email'] = cemail
                            self.session['name'] = user.first_name.title(
                            ) + " " + user.last_name.title()
                            self.session['first_name'] = user.first_name.title(
                            )
                            self.session['user_id'] = user.key.urlsafe()
                            self.session['register_type'] = user.register_type
                            self.session[
                                'Profile_url'] = self.get_profile_image()
                            check_cookie.last_active = time.time()
                            check_cookie.put()

        unauthorized_routes = [
            "/", "/log-in", "/sign-up", "/help", "/teach", "social-login",
            "/reset-password", "/reset-password-email"
        ]
        if self.request.path in unauthorized_routes:
            print(self.request.path)
        else:
            if not self.session.get("email"):
                self.redirect('/log-in')

        try:
            # Dispatch the request.
            webapp2.RequestHandler.dispatch(self)

        finally:
            # Save all sessions.
            self.session_store.save_sessions(self.response)
Exemple #3
0
def get_course_listing_by_prefix(course_num_prefix):
    course_num_prefix = __fix_course_num(course_num_prefix)
    json_array = memcache.get(course_num_prefix)
    if json_array is None:
        courses = Course.query(ndb.AND(Course.course_num >= course_num_prefix, \
                                   Course.course_num <= course_num_prefix +'z'))\
              .fetch(limit=5, projection=[Course.course_num])
        json_array = []
        for course in courses:
            course_dict = {}
            key_str = course.key.urlsafe()
            course_dict[course.course_num] = key_str
            json_array.append(course_dict)
        if not memcache.add(course_num_prefix,json_array):
            logging.error('Memcache set failed')
    return json.dumps(json_array)
Exemple #4
0
def touch_alert(product_key):  # cron at specific time?
    #product_entity = Product.get_by_id(product_key)
    product_entity = fetch_by_urlsafe_key(product_key)
    current = product_entity.current
    asin = product_entity.key.id()
    query1 = Monitor.query(
        ndb.AND(Monitor.target == asin, Monitor.switch == True))
    query2 = query1.filter(Monitor.threshold >= current)
    query3 = query2.filter(Monitor.alert == False)
    touch_alert_list = query3.fetch()
    #touch_alert_list = Monitor.query(
    #    ndb.AND(Monitor.target == asin,
    #        ndb.AND(Monitor.threshold > current,
    #            ndb.AND(Monitor.switch == True,
    #                Monitor.alert == False)))).fetch()
    return touch_alert_list
Exemple #5
0
    def post(self):
        semail = self.request.get('email')
        password = self.request.get('password')
        discountorX = Discountor.query(
            ndb.AND(Discountor.email == semail,
                    Discountor.password == password))

        if not discountorX.get():
            message = 'no'
            template_values = {'message': message}
            template = JINJA_ENVIRONMENT.get_template('login.html')
            self.response.write(template.render(template_values))
        else:
            template_values = {'discountorOpenid': semail}
            template = JINJA_ENVIRONMENT.get_template('price.html')
            self.response.write(template.render(template_values))
Exemple #6
0
    def populate_players(self):
        """ Fill in the players and explayers array from a datastore query """
        self.players = []
        self.explayers = []

        # Query the players in the team
        query = ffdb.FFDBTeamPlayer.query().filter(
            ndb.AND(ffdb.FFDBTeam.year == self.year,
                    ffdb.FFDBTeam.userid == self.userid))

        for player in query:
            entry = FFTeamPlayer(db_entry=player)
            self.populate_player(entry)

        # Make sure the team has players in every entry in the squad
        self.fill_squad()
Exemple #7
0
    def get_user_games(self, request):
        """Get all active Games for a User"""

        # check user name
        if not User.query(User.name == request.player_name).get():
            raise endpoints.ConflictException(
                'No user named {} exists!'.format(request.player_name))
        else:
            games = Game.query(
                ndb.AND(
                    Game.is_active == True,
                    ndb.OR(
                        Game.player_1_name == request.player_name,
                        Game.player_2_name == request.player_name))).fetch()
            return StringMessages(
                message=[game.key.urlsafe() for game in games])
Exemple #8
0
 def get(self):
     al = self.request.get('m')
     if al:
         alert = fns.alert(int(al))
     else:
         alert = False
     areas = teachme_db.areas.query().order(teachme_db.areas.name)
     mentors = {}
     for a in areas:
         mentors[a.key.id()] = teachme_db.teacher.query(
             ndb.AND(teachme_db.teacher.areas == a.key.id(),
                     teachme_db.teacher.aceptado == True,
                     teachme_db.teacher.profile_pic != None)).fetch()
         # MentorHelper.sort_mentors(mentors[a.key.id()])
         shuffle(mentors[a.key.id()])
     self.render("main_page.html", mentors=mentors, alert=alert)
Exemple #9
0
def getActiveRideOffers():
    import params
    import date_time_util as dtu
    from datetime import timedelta

    qry = RideOffer.query(
        ndb.AND(
            RideOffer.active == True,
            ndb.OR(
                RideOffer.programmato == True,
                RideOffer.start_datetime >= dtu.removeTimezone(dtu.nowCET()) -
                timedelta(minutes=params.TIME_TOLERANCE_MIN)
                # might be redundant as the filter is also applied afterwards
            )))
    offers = qry.fetch()
    return offers
Exemple #10
0
 def get(self):
     cur_user = users.get_current_user()
     if cur_user:
         query = Tag.query(
             ndb.AND(Tag.tag == self.request.query_string,
                     Tag.user == cur_user))
         if query.iter().has_next():
             tag = query.iter().next()
             requestQuery = Request.query(Request.tag == tag.tag)
             while requestQuery.iter().has_next():
                 requestQuery.iter().next().key.delete()
             tag.key.delete()
         else:
             self.error(404)
     else:
         self.error(401)
Exemple #11
0
def getActiveRideOffersDriver(driver_id):
    import params
    import date_time_util as dtu
    from datetime import timedelta
    now_with_tolerance = dtu.removeTimezone(dtu.nowCET()) - timedelta(minutes=params.TIME_TOLERANCE_MIN)
    qry = RideOffer.query(
        ndb.AND(
            RideOffer.active == True,
            RideOffer.driver_id == driver_id,
            ndb.OR(
                RideOffer.programmato == True,
                RideOffer.start_datetime >= now_with_tolerance
            )
        )
    ).order(RideOffer.start_datetime)
    return qry.fetch()
 def delete_item(self, request):
     result = DB_Item.query(
         ndb.AND(DB_Item.res_name == request.res_name,
                 DB_Item.item_name == request.item_name)).fetch()
     RESPONSE = Response()
     if len(result) == 0:
         logging.info('Attempted to delete ' + request.item_name + ' for ' +
                      request.res_name + '. No items returned.')
         RESPONSE.response = False
     else:
         item = result[0]
         item.key.delete()
         logging.info('Deleted ' + item.item_name + ' for ' +
                      request.res_name)
         RESPONSE.response = True
     return RESPONSE
Exemple #13
0
    def get(self):
        key = self.request.get('key')
        logging.info('ReceievedEmailTask: {0}'.format(key))
        email = ndb.Key(urlsafe=key).get()

        matchMappings = AttachmentMapping.query(
            ndb.AND(
                ndb.OR(
                    AttachmentMapping.sender == email.sender,
                    AttachmentMapping.sender == '',
                ),
                AttachmentMapping.emailPrefix == email.addressPrefix)).fetch()
        logging.info(matchMappings)

        email.processed = True
        email.put()
Exemple #14
0
 def get(self, schedule_version, set_live):
     if not self.SetSchedule(int(schedule_version)):
         return
     self.schedule.is_live = (set_live == '1')
     self.schedule.last_update = datetime.datetime.now()
     if self.schedule.is_live:
         for schedule in Schedule.query(
                 ndb.AND(Schedule.competition == self.competition.key,
                         Schedule.is_live == True)).iter():
             schedule.is_live = False
             schedule.put()
     self.schedule.put()
     self.redirect(
         webapp2.uri_for('edit_schedule',
                         competition_id=self.competition.key.id(),
                         schedule_version=self.schedule.key.id()))
Exemple #15
0
    def get_reviewable_voiceover_applications(cls, user_id):
        """Returns a list of voiceover application which a given user can
        review.

        Args:
            user_id: str. The id of the user trying to make this query.
                As a user cannot review their own voiceover application, so the
                voiceover application created by the user will be excluded.

        Returns:
            list(GeneralVoiceoverApplicationModel). The list of voiceover
            applications which the given user can review.
        """
        return cls.query(
            ndb.AND(cls.author_id != user_id,
                    cls.status == STATUS_IN_REVIEW)).fetch()
Exemple #16
0
    def get(self, id=None):
        #If GET is for individual log, get by ID and respond
        if id:
            log = ndb.Key(urlsafe=id).get()
            log_d = log.to_dict()
            log_d['date'] = str(log_d['date'])
            log_d['self'] = "/logs/" + id
            self.response.content_type = 'application/json'
            self.response.write(json.dumps(log_d, indent=2))

        #Otherwise, return all logs for user
        else:
            #If user was not specified, return error
            if ('user' not in self.request.headers):
                ErrorHandler(
                    self, 400,
                    "'user' must be submitted as a header with GET request")
                return

            #If date was passed as a query parameter, filter by the date and user
            if (self.request.get('date') != ''):
                q_date = datetime.strptime(self.request.get('date'),
                                           '%m-%d-%Y').date()
                self.response.write(q_date)
                user_name = self.request.headers['user']
                logs_dict = [
                    logs.to_dict() for logs in Log.query(
                        ndb.AND(Log.user == user_name, Log.date == q_date))
                ]
                for logs in logs_dict:
                    logs['date'] = str(logs['date'])
                    logs['self'] = '/logs/' + logs['id']
                self.response.content_type = 'application/json'
                self.response.write(json.dumps(logs_dict, indent=2))

            #Otherwise, just filter by the user
            else:
                user_name = self.request.headers['user']
                logs_dict = [
                    logs.to_dict() for logs in Log.query(
                        Log.user == user_name).order(-Log.date)
                ]
                for logs in logs_dict:
                    logs['date'] = str(logs['date'])
                    logs['self'] = '/logs/' + logs['id']
                self.response.content_type = 'application/json'
                self.response.write(json.dumps(logs_dict, indent=2))
Exemple #17
0
    def get(self):
        dashboard_name = self.request.get('user', DEFAULT_DASHBOARD_NAME)
        todayNice = datetime.now().strftime(
            '%A %d, %b %Y')  #e.g. Tuesday 03, Nov 2015]
        user = users.get_current_user()
        if user:
            url = users.create_logout_url(self.request.uri)
            url_linktext = 'Logout'
            today = datetime.now().strftime('%Y-%m-%d')
            date_object = datetime.strptime(today, '%Y-%m-%d')
            query = Rating.query(
                ancestor=dashboard_key(dashboard_name),
                filters=ndb.AND(Rating.date >= date_object,
                                Rating.date < date_object + timedelta(days=1),
                                Rating.author.email == user.email()))
            chart_x_label = "['x',"
            chart_productivity = "['Productivity',"
            chart_stress = "['Stress',"
            chart_challenge = "['Challenge',"
            chart_abilities = "['Abilities',"
            for r in query.fetch():
                t0 = r.timeframe
                t1 = 1 + int(r.timeframe)
                chart_x_label += "'" + str(t0) + "-" + str(t1) + "',"
                chart_productivity += r.productivity + ","
                chart_stress += r.stress + ","
                chart_challenge += r.challenge + ","
                chart_abilities += r.abilities + ","
            chart_x_label += "]"
            chart_productivity += "]"
            chart_stress += "]"
            chart_challenge += "]"
            chart_abilities += "]"

            chart_data = chart_x_label + "," + chart_productivity + "," + chart_stress + "," + chart_challenge + "," + chart_abilities
            template_values = {
                'user': user,
                'chart_data': chart_data,
                'url_linktext': url_linktext,
                'today': todayNice,
            }
        else:
            url = users.create_login_url(self.request.uri)
            url_linktext = 'Login'

        template = JINJA_ENVIRONMENT.get_template('viz.html')
        self.response.write(template.render(template_values))
    def get(self):
        content = JINJA_ENV.get_template("templates/divsForCalendar.html")

        # THIS WILL BREAK AT THE END OF DEC OR EARLY JAN.

        #year = Event.start_time.year
        week = helpers.get_this_week()
        start_week = datetime(2018, week[0][0], week[0][1], 0, 0)
        end_week = datetime(2018, week[-1][0], week[-1][1], 0, 0)

        events = Event.query().filter(
            ndb.AND(Event.start_time >= start_week,
                    Event.start_time <= end_week)).fetch()

        logout = users.create_logout_url('/')

        listOfDays = ["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"]

        for i in range(len(week)):
            week[i].append(listOfDays[i])

        def _get_dow(t):
            return listOfDays[helpers._dow(t.month, t.day, t.year)]

        def _get_time(t):
            return t.hour

        data = []
        for event in events:
            start_dow = _get_dow(event.start_time)
            end_dow = _get_dow(event.final_time)

            start_time = event.start_time.hour
            end_time = event.final_time.hour

            data.append([
                " ".join([start_dow, str(start_time)]),
                " ".join([end_dow, str(end_time)]), event.event_name
            ])

        print(data)

        self.response.write(
            content.render(week=imap(
                lambda x: x[2] + " " + str(x[0]) + "/" + str(x[1]), week),
                           data=json.dumps(data),
                           logout=logout))
Exemple #19
0
    def get(self):
        try:
            id = self.request.GET["id"]
            currentuser = ndb.Key(urlsafe=id).get()
            user = self.request.get("user", "").strip()

            user = Register.query(Register.username == user)

            if currentuser and user.count() != 0:
                for i in user:
                    user = i

                unfollow = Follow.query(
                    ndb.AND(Follow.username == currentuser.username,
                            Follow.usernameToFollow == user.username))

                if unfollow.count() == 0:
                    currentuser.follow = currentuser.follow + 1
                    currentuser.put()
                    user.followers = user.followers + 1
                    user.put()

                    follow = Follow(username=currentuser.username,
                                    usernameToFollow=user.username)
                    follow.put()
                    time.sleep(1)

                    self.redirect("/user/showusers?search=" + user.username +
                                  "&id=" + id)
                else:
                    currentuser.follow = currentuser.follow - 1
                    currentuser.put()
                    user.followers = user.followers - 1
                    user.put()

                    for i in unfollow:
                        unfollow = i

                    unfollow.key.delete()
                    self.redirect("/user/showusers?search=" + user.username +
                                  "&id=" + id)
            else:
                self.response.write("An error occurred.")
                return
        except:
            self.response.write("An error occurred.")
            return
Exemple #20
0
    def get_query_set(self):
        qs = self.root_query_set
        qs._filtered = False
        lookup_params = self.params.copy()  # a dictionary of the query string
        for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR,
                  TO_FIELD_VAR):
            if i in lookup_params:
                del lookup_params[i]
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[str(key)] = value

            _field, lookup = key.split('__')
            field = getattr(self.model, _field)
            if lookup == 'bool':
                qs = qs.filter(field == bool(int(value)))
            elif lookup in ['iexact', 'exact']:
                qs = qs.filter(field == value)
            # TODO: more
            qs._filtered = True

        if self.search_fields and self.query:
            if len(self.search_fields) == 1:
                # simple case just do a filter
                field = getattr(self.model, self.search_fields[0])
                qs = qs.filter(field == self.query)
                qs._filtered = True
            else:
                fields = [getattr(self.model, f) for f in self.search_fields]
                queries = [ndb.AND(field == self.query) for field in fields]
                qs = qs.filter(ndb.OR(*queries))
                qs._filtered = True

        if self.order_field:
            filtered = qs._filtered
            field = getattr(self.model, self.order_field, None)
            if field:
                if self.order_type == 'desc':
                    qs = qs.order(-field)
                else:
                    qs = qs.order(field)
                qs._filtered = filtered

        return qs
Exemple #21
0
    def get(self):
        for incident in models.Incident.query(
                ndb.AND(models.Incident.location == None,
                        models.Incident.geocoding_failed != True)).order(
                            models.Incident.geocoding_failed,
                            -models.Incident.time).fetch(
                                config.GEOCODING_BATCH_SIZE):

            address = urllib.quote_plus(
                # In the incident data, "/" is used to denote
                # intersections (e.g., "3rd Ave / Pike St"). The
                # Google Geocoding API does not understand "/" to mean
                # an intersection, though; it uses "&", so we replace
                # "/" with "&" in the address.
                incident.address.replace('/', '&') + ', Seattle, WA, USA')

            logging.info('Geocoding address: %s', incident.address)
            url = ('https://maps.googleapis.com/maps/api/geocode/'
                   'json?address={address}&key={key}').format(
                       address=address, key=config.GEOCODING_API_KEY)
            logging.info('Request:\n  %s', url)

            res = json.loads(urlfetch.fetch(url).content)

            # See
            # https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes
            # for status codes.
            #
            # The most common cause of geocoding failures is addresses
            # that are cross-streets, like "3rd Av / Pike St". At some
            # point, we should figure out how to geocode these types
            # of addresses.
            status = res['status']
            if status != 'OK':
                logging.error('Status: %s\n', status)

                if status == 'ZERO_RESULTS':
                    incident.geocoding_failed = True
                    incident.put_async()
                continue

            location = res['results'][0]['geometry']['location']
            logging.info('Location: %s\n', location)
            incident.location = ndb.GeoPt(lat=location['lat'],
                                          lon=location['lng'])
            incident.put()
Exemple #22
0
def database_read():
    name = request.form['name2']
    #email = request.form['email2']
    password = request.form['password2']
    message = ''
    
    
    query = User.query(ndb.AND(User.name == name, User.password == password))
    result = query.get()
    if result is None:
        message = 'name,password error'
        email = ''
        return render_template('databaseRead.html', name2=name, email2=email, password2=password, message=message)
    else:
        email = result.email
        #return result.email
        return render_template('databaseRead.html', name2=name, email2=email, password2=password, message=message)
Exemple #23
0
    def get(self):
        license = self.request.get('license')
        rate_limit = self.request.get('rate_limit')
        gql = self.request.get('gql')
        if gql is not None and gql == 'true':
            q = ndb.gql("SELECT * FROM NDBProject WHERE license = '%s' "\
                            "AND rating >= %s" % (license, rate_limit))
        else:
            q = NDBProject.query(
                ndb.AND(NDBProject.license == license,
                        NDBProject.rating >= int(rate_limit)))

        data = []
        for entity in q:
            data.append(entity)
        self.response.headers['Content-Type'] = "application/json"
        self.response.out.write(json.dumps(data, default=serialize))
    def post(self):
        email = self.request.get('email')
        pw = self.request.get('password')

        user = User.query(ndb.AND(\
                    User.email == email, User.pw_hash == hash_str(pw))).get()

        if user:
            self.response.headers.add_header(
                'Set-Cookie', 'user_id=%s, Expires=%s; Path=/'% \
                    (make_secure_val(str(user.key.id())), str(7*24*3600))\
            )
            time.sleep(0.1)
            return self.redirect('/')
        else:
            error = "Username and/or Password don't match!"
            return self.render('login.html', error=error)
    def getEarlyNonWorkshopSessions(self, request):
        """Returns non-workshop sessions occurring before 7pm"""

        sessions = Session.query(
            ndb.AND(Session.startTime != None,
                    Session.startTime <= timed(hour=19)))

        filtered_sessions = []
        for session in sessions:
            if 'workshop' in session.typeOfSession:
                continue
            else:
                filtered_sessions.append(session)

        return SessionForms(items=[
            self._copySessionToForm(session) for session in filtered_sessions
        ])
def CheckRate(mobileNumber):
    logging.info("Checking rate for: " + mobileNumber)
    last24hours = datetime.now() - timedelta(days=1)

    query = RateManager.query(
        ndb.AND(RateManager.created > last24hours,
                RateManager.mobileNumber == mobileNumber))
    resultCount = query.count()
    if (resultCount < 40):
        rate = RateManager()
        rate.mobileNumber = mobileNumber
        rate.put
        logging.info("Rate is fine for:" + mobileNumber)
        return True

        logging.info("Rate exceeded for:" + mobileNumber)
    return False
Exemple #27
0
    def getSessionsByTypeTime(self, request):
        """Returns all non workshop sessions held before 7 pm. """

        sessions = Session.query(
            ndb.AND(Session.startTime != None,
                    Session.startTime <= timed(hour=19)))

        filtered_sessions = []
        for session in sessions:
            if 'workshop' == session.typeOfSession:
                continue
            else:
                filtered_sessions.append(session)

        return SessionForms(items=[
            self._copySessionToForm(session) for session in filtered_sessions
        ])
Exemple #28
0
    def _cacheAnnouncement():
        """Create Announcement & assign to memcache; used by
        memcache cron job & putAnnouncement().
        """
        confs = Conference.query(
            ndb.AND(Conference.seatsAvailable <= 5,
                    Conference.seatsAvailable > 0)).fetch(
                        projection=[Conference.name])

        if confs:
            announcement = ANNOUNCEMENT_TPL % (', '.join(conf.name
                                                         for conf in confs))
            memcache.set(MEMCACHE_ANNOUNCEMENTS_KEY, announcement)
        else:
            announcement = ""
            memcache.delete(MEMCACHE_ANNOUNCEMENTS_KEY)
        return announcement
Exemple #29
0
    def get_voiceover_applications(cls, target_type, target_id, language_code):
        """Returns a list of voiceover applications submitted for a give entity
        in a given language.

        Args:
            target_type: str. The type of entity.
            target_id: str. The ID of the targeted entity.
            language_code: str. The code of the language in which the voiceover
                application is submitted.

        Returns:
            list(GeneralVoiceoverApplicationModel). The list of voiceover
            application which is submitted to a give entity in a given language.
        """
        return cls.query(
            ndb.AND(cls.target_type == target_type, cls.target_id == target_id,
                    cls.language_code == language_code)).fetch()
Exemple #30
0
def get_content_list(per_page=20):
    """
    Create a query over ``Content`` objects using query string parameters.

    :param per_page:    number of items to return per page
    :returns:           ``QueryResult`` object
    """
    search = request.params.getunicode('q', '').strip()
    status = request.params.get('status')
    license = request.params.get('license')
    votes = request.params.get('votes')
    page = int(request.params.get('p', '1'))

    q = Content.query()
    if search:
        keywords = Content.get_keywords(search)
        if len(keywords) > 1:
            q = q.filter(ndb.AND(*[Content.keywords == kw for kw in keywords]))
        if len(keywords) == 1:
            q = q.filter(Content.keywords == keywords[0])
    if status:
        q = q.filter(Content.status == status)
    if license == 'free':
        q = q.filter(Content.is_free == True)
    elif license == 'nonfree':
        q = q.filter(Content.is_free == False)
    elif license == 'unknown':
        q = q.filter(Content.license == None)
    if votes == 'asc':
        q = q.order(+Content.votes)
    elif votes == 'desc':
        q = q.order(-Content.votes)
    q = q.order(-Content.updated)

    count = q.count()

    if not count:
        return QueryResult([], count, 1, 1)

    npages = int(math.ceil(count / per_page))

    if page * per_page > count:
        page = npages

    offset = int(per_page * (page - 1))
    return QueryResult(q.fetch(per_page, offset=offset), count, page, npages)