Exemplo n.º 1
0
    def build_reporting_unit(self, pc_id, checkpoints, tasks):
        url_base = '{protocol}://{domain}'.format(
            protocol='http' if util.is_localhost() else 'https',
            domain=('localhost:8888'
                    if util.is_localhost() else os.environ['HOSTING_DOMAIN']),
        )

        # Find the right task for this project cohort
        c = next(c for c in checkpoints if c.project_cohort_id == pc_id)
        t = next(t for t in tasks if t.checkpoint_id == c.uid)

        # Assemble the URLs that RServe will need to post back to.
        dataset_url = '{base}/api/datasets?parent_id={parent_id}'.format(
            base=url_base,
            parent_id=pc_id,
        )
        task_attachment_url = '{base}/api/tasks/{task_id}/attachment'.format(
            base=url_base,
            task_id=t.uid,
        )
        return {
            'project_cohort_id': pc_id,
            'post_url': dataset_url,
            'post_task_attachment_url': task_attachment_url,
        }
Exemplo n.º 2
0
def get_url(script):
    return '{protocol}://{domain}/api/scripts/{script}'.format(
        protocol='http' if util.is_localhost() else 'https',
        domain=('localhost:9080'
                if util.is_localhost() else os.environ['RSERVE_DOMAIN']),
        script=script,
    )
    def setUp(self):
        """Sets self.testbed and activates it, among other global settings.

        This function (noticeably not named with PERTS-standard underscore
        case) is automatically called when starting a test by the unittest
        module. We use it for basic configuration and delegate further set
        up to the more canonically named set_up() of inheriting classes.
        """
        if not util.is_localhost():
            # Logging test activity in production causes errors. This
            # suppresses all logs of level critical and lower, which means all
            # of them. See
            # https://docs.python.org/2/library/logging.html#logging.disable
            logging.disable(logging.CRITICAL)

        # Start a clean testing environment for one test.
        self.testbed = testbed.Testbed()
        self.testbed.activate()

        # We have to use a memcache stub so that appstats doesn't complain in
        # production.
        self.testbed.init_memcache_stub()

        # NDB has lots of fancy caching features, whic are normally great, but
        # get in the way of testing consistency.
        # https://cloud.google.com/appengine/docs/python/ndb/cache
        ndb_context = ndb.get_context()
        ndb_context.set_cache_policy(lambda x: False)
        ndb_context.set_memcache_policy(lambda x: False)

        # Let inheriting classes to their own set up.
        if hasattr(self, 'set_up'):
            self.set_up()
Exemplo n.º 4
0
    def write(self, template_filename, template_path=None, **kwargs):
        if template_path is None:
            template_path = 'templates'
        jinja_environment = jinja2.Environment(
            autoescape=True,
            extensions=['jinja2.ext.autoescape'],
            loader=jinja2.FileSystemLoader(template_path),
        )

        # Jinja environment filters:

        @jinja2.evalcontextfilter
        def jinja_json_filter(eval_context, value):
            """Seralize value as JSON and mark as safe for jinja."""
            return jinja2.Markup(json.dumps(value))

        jinja_environment.filters['to_json'] = jinja_json_filter

        # default parameters that all views get
        kwargs['google_logout_url'] = app_engine_users.create_login_url()
        kwargs['hosting_domain'] = os.environ['HOSTING_DOMAIN']
        kwargs['is_localhost'] = util.is_localhost()

        # Try to load the requested template. If it doesn't exist, replace
        # it with a 404.
        try:
            template = jinja_environment.get_template(template_filename)
        except jinja2.exceptions.TemplateNotFound:
            return self.http_not_found()

        # Render the template with data and write it to the HTTP response.
        self.response.write(template.render(kwargs))
Exemplo n.º 5
0
    def connect_to_db(self):
        """Establish connection to MySQL db instance.

        Either Google Cloud SQL or local MySQL server. Detects environment with
        functions from util module.
        """
        if util.is_localhost() or util.is_codeship():
            credentials = {
                'host': self.local_ip,
                'port': self.local_port,
                'user': self.local_user,
                'passwd': self.local_password
            }
        else:
            # Note: for second generation cloud sql instances, the instance
            # name must include the region, e.g. 'us-central1:production-01'.
            credentials = {
                'unix_socket': '/cloudsql/{app_id}:{instance_name}'.format(
                    app_id=app_identity.get_application_id(),
                    instance_name=self.cloud_sql_instance),
                'user': self.cloud_sql_user,
            }
        if self.db_name:
            credentials['db'] = self.db_name

        # Although the docs say you can specify a `cursorclass` keyword
        # here as an easy way to get dictionaries out instead of lists, that
        # only works in version 1.2.5, and App Engine only has 1.2.4b4
        # installed as of 2015-03-30. Don't use it unless you know the
        # production library has been updated.
        # tl;dr: the following not allowed!
        # self.connection = MySQLdb.connect(
        #     charset='utf8', cursorclass=MySQLdb.cursors.DictCursor, **creds)
        self.connection = MySQLdb.connect(charset='utf8', **credentials)
        self.cursor = self.connection.cursor()
Exemplo n.º 6
0
    def get(self, template_name):
        """Overrides BaseHandler.get and session management for max speed."""
        params = {}

        # Needed for shortcut to register with neptune.
        if util.is_localhost():
            params['neptune_domain'] = 'localhost:8080'
            params['neptune_protocol'] = 'http'
            params['triton_domain'] = 'localhost:10080'
            params['triton_protocol'] = 'http'
        else:
            params['neptune_domain'] = os.environ['NEPTUNE_DOMAIN']
            params['neptune_protocol'] = 'https'
            params['triton_domain'] = os.environ['TRITON_DOMAIN']
            params['triton_protocol'] = 'https'

        # Provide the current template name to jinja so it can highlight the
        # active navbar link.
        params['template_name'] = template_name

        template = template_name + '.html'
        if not os.path.isfile('templates/' + template):
            template, params = self.http_not_found()
        jinja_environment = jinja2.Environment(
            autoescape=True, loader=jinja2.FileSystemLoader('templates'))
        html_str = jinja_environment.get_template(template).render(params)
        self.response.write(html_str)
    def setUp(self):
        """Sets self.testbed and activates it, among other global settings.

        This function (noticeably not named with PERTS-standard undrescore
        case) is automatically called when starting a test by the unittest
        module. We use it for basic configuration and delegate further set
        up to the more canonically named set_up() of inheriting classes.
        """
        if not util.is_localhost():
            # Logging test activity in production causes errors. This
            # suppresses all logs of level critical and lower, which means all
            # of them. See
            # https://docs.python.org/2/library/logging.html#logging.disable
            logging.disable(logging.CRITICAL)

        # Start a clean testing environment for one test.
        self.testbed = testbed.Testbed()
        self.testbed.activate()

        # We have to use a memcache stub so that appstats doesn't complain in
        # production.
        self.testbed.init_memcache_stub()

        # Let inheriting classes to their own set up.
        if hasattr(self, 'set_up'):
            self.set_up()
Exemplo n.º 8
0
    def render(self):
        """Interpolate data into an html string.

        Ignores `{items}` b/c that's for digest().
        """
        # Add environment and user details to params.
        protocol = 'http' if util.is_localhost() else 'https'
        domain = ('localhost:3000'
                  if util.is_localhost() else os.environ['HOSTING_DOMAIN'])
        params = dict(
            self.template_params,
            triton_domain='{}://{}'.format(protocol, domain),
            user_id=self.user_id,
            short_user_id=Notification.convert_uid(self.user_id),
        )
        return self.get_template().render(**params)
Exemplo n.º 9
0
    def get_credentials(self):
        """Establish connection to MySQL db instance.

        Either Google Cloud SQL or local MySQL server. Detects environment with
        functions from util module.
        """
        if util.is_localhost() or util.is_codeship():
            credentials = {
                'host': self.local_ip,
                'port': self.local_port,
                'user': self.local_user,
                'passwd': self.local_password
            }
        else:
            # Note: for second generation cloud sql instances, the instance
            # name must include the region, e.g. 'us-central1:production-01'.
            credentials = {
                'unix_socket':
                '/cloudsql/{app_id}:{instance_name}'.format(
                    app_id=app_identity.get_application_id(),
                    instance_name=self.cloud_sql_instance),
                'user':
                self.cloud_sql_user,
            }
        if self.db_name:
            credentials['db'] = self.db_name

        return credentials
Exemplo n.º 10
0
def send(template_data={}, **kwargs):

    # Determine if message should send
    if util.is_localhost() and not config.should_deliver_smtp_dev:
        logging.info('Email not sent, check config!')
        return None

    subject = render(kwargs['subject'], **template_data)

    # Determine if using html string or a template
    body = ''
    if 'body' in kwargs:
        body = render(kwargs['body'], **template_data)
    elif 'template' in kwargs:
        body = render_template(kwargs['template'], **template_data)

    # JSON for Mandrill HTTP POST request
    json_mandrill = {
        "key": config.mandrill_api_key,
        "message": {
            "html": body,
            "subject": subject,
            "from_email": config.from_server_email_address,
            "from_name": config.from_server_name,
            "inline_css": True,
            "to": format_to_address(kwargs['to_address'])
        }
    }

    # URL for Mandrill HTTP POST request
    url = "https://mandrillapp.com/api/1.0/messages/send.json"
    rpc = urlfetch.create_rpc()
    urlfetch.make_fetch_call(
        rpc,
        url=url,
        payload=json.dumps(json_mandrill),
        method=urlfetch.POST,
        headers={'Content-Type': 'application/x-www-form-urlencoded'})

    try:
        result = rpc.get_result()
    except urlfetch.DownloadError:
        # Request timed out or failed. On localhost this can be from network
        # issues.
        logging.error("Mandrill RPC failed.")
        return None

    result_info = json.loads(result.content)[0]

    logging.info("Mandrill response: {} {}"
                 .format(result.status_code, result_info))

    if result.status_code == 200:
        if result_info['status'] != 'sent':
            logging.error("Email failed to send.")
    else:
        logging.error("Mandrill response wasn't a 200.")

    return result
Exemplo n.º 11
0
 def do_wrapper(self, *args, **kwargs):
     try:
         output = self.do(*args, **kwargs)
     except Exception as error:
         logging.error("{}".format(error))
         if debug:
             import traceback
             self.response.write('<pre>{}</pre>'.format(
                 traceback.format_exc()))
         else:
             self.response.write("We are having technical difficulties.")
         return
     if output is not None:
         # do methods might not put out rendering info
         # todo: they really should always do that. make sure they do then
         # remove this check
         template = output[0]
         params = output[1]
         if len(output) >= 3:
             template_directory = output[2]
         else:
             template_directory = 'templates'
         jinja_environment = jinja2.Environment(
             autoescape=True,
             loader=jinja2.FileSystemLoader(template_directory),
             # # These change jinja's template syntax
             # variable_start_string='[[',
             # variable_end_string=']]',
             # block_start_string='[%',
             # block_end_string='%]'
         )
         jinja_environment.globals['gae_mini_profiler_includes'] = (
             gae_mini_profiler.templatetags.profiler_includes)
         # Jinja environment filters:
         jinja_environment.filters['tojson'] = json.dumps
         # default parameters that all views get
         user = self.get_current_user()
         normal_user = self.get_current_user(method='normal')
         params['user'] = user
         params['normal_user'] = normal_user
         params['config'] = config
         params['currently_impersonating'] = user != normal_user
         params['connected_to_facebook'] = bool(self.facebook_cookie())
         if params['connected_to_facebook']:
             params['facebook_user'] = self.get_third_party_auth('facebook')
         else:
             params['facebook_user'] = None
         params['connected_to_google'] = app_engine_users.get_current_user()
         params['google_user'] = app_engine_users.get_current_user()
         params['google_admin'] = app_engine_users.is_current_user_admin()
         params[
             'current_url'] = self.request.path + '?' + self.request.query_string
         params['is_localhost'] = util.is_localhost()
         if debug:
             params['session'] = json.dumps(self.session)
         # render
         html_str = jinja_environment.get_template(template).render(params)
         self.response.write(html_str)
Exemplo n.º 12
0
    def notify_for_single_report(self, program, team, classroom=None):
        """Notifications for class contact or all members re: one report."""
        if not team.report_reminders:
            logging.info(
                "{} has report reminders disabled; not notifying".format(
                    team.uid))
            return

        if classroom:
            recipients = [User.get_by_id(classroom.contact_id)]
        else:
            recipients = User.query_by_team(team.uid)

        protocol = 'http' if util.is_localhost() else 'https'
        # Note that reports are hosted by the local _backend_ gae sdk, not the
        # react-app dev server on :3000. But for now we're just pointing to the
        # list of a team's reports, which _is_ on :3000.
        domain = ('localhost:3000'
                  if util.is_localhost() else os.environ['HOSTING_DOMAIN'])

        reports_page = '{}://{}/teams/{}/reports'.format(
            protocol, domain, team.short_uid)

        # If we do want to link directly to the report, we'll have to wrestle
        # with authentication and what that looks like. We can either generate
        # a token right here (but that would be the link was shareable, and it
        # would expire, both of which seem wrong) or build some additional
        # client code that would know how to redirect an unauthed user to
        # login and back.

        notes = []
        for user in recipients:
            notes.append(
                Notification.create(
                    user_id=user.uid,
                    type='report',
                    template_params={
                        'context_name':
                        classroom.name if classroom else team.name,
                        'first_name': user.first_name,
                        'program_name': program.name,
                        'url': reports_page,
                    }))
        return notes
Exemplo n.º 13
0
    def report_link(self, report):
        parent_kind = SqlModel.get_url_kind(report.parent_id)
        short_id = SqlModel.convert_uid(report.parent_id)

        if report.gcs_path:
            platform = 'triton'
            prefix = ''
            view_path = '/api/{parent_kind}/{id}/reports/{filename}'.format(
                parent_kind=parent_kind,
                id=short_id,
                filename=report.filename,
            )
        elif report.dataset_id:
            platform = 'neptune'
            prefix = '{protocol}://{domain}'.format(
                protocol='http' if util.is_localhost() else 'https',
                domain=('localhost:8888' if util.is_localhost() else
                        os.environ['NEPTUNE_DOMAIN']),
            )
            view_path = '/datasets/{ds_id}/{template}/{filename}'.format(
                ds_id=SqlModel.convert_uid(report.dataset_id),  # short form
                template=report.template,
                filename=report.filename,
            )

        # Permit report clients to query some data about participation.
        parent_path = '/api/{parent_kind}/{id}'.format(parent_kind=parent_kind,
                                                       id=short_id)
        data_path = '/api/{parent_kind}/{id}/report_data'.format(
            parent_kind=parent_kind, id=short_id)

        link_jwt = jwt_helper.encode(
            {
                'allowed_endpoints': [
                    self.get_endpoint_str(platform=platform, path=view_path),
                    self.get_endpoint_str(platform='triton', path=parent_path),
                    self.get_endpoint_str(platform='triton', path=data_path),
                ]
            },
            expiration_minutes=(30 * 24 * 60),  # thirty days
        )

        return util.set_query_parameters(prefix + view_path, token=link_jwt)
Exemplo n.º 14
0
    def write(self, template_filename, template_path='templates', **kwargs):
        jinja_environment = self.get_jinja_environment(template_path)

        # Jinja environment filters:

        @jinja2.evalcontextfilter
        def jinja_json_filter(eval_context, value):
            """Seralize value as JSON and mark as safe for jinja."""
            return jinja2.Markup(json.dumps(value))

        jinja_environment.filters['to_json'] = jinja_json_filter

        def format_datetime(value):
            # Formats datetime as Ex: "January 9, 2015"
            return '{dt:%B} {dt.day}, {dt.year}'.format(dt=value)

        jinja_environment.filters['datetime'] = format_datetime

        user = self.get_current_user()

        # default parameters that all views get
        kwargs['user'] = user.to_client_dict()
        # Python keeps time to the microsecond, but we don't need it, and
        # it's easier to render as ISO 8601 without it.
        kwargs['server_time'] = datetime.datetime.today().replace(
            microsecond=0)
        kwargs['is_localhost'] = util.is_localhost()
        kwargs['hosting_domain'] = os.environ['HOSTING_DOMAIN']
        kwargs['yellowstone_domain'] = os.environ['YELLOWSTONE_DOMAIN']
        kwargs['browser_api_key'] = (os.environ['LOCALHOST_BROWSER_API_KEY']
                                     if util.is_localhost() else
                                     os.environ['DEPLOYED_BROWSER_API_KEY'])

        # Try to load the requested template. If it doesn't exist, replace
        # it with a 404.
        try:
            template = jinja_environment.get_template(template_filename)
        except jinja2.exceptions.TemplateNotFound:
            logging.error("TemplateNotFound: {}".format(template_filename))
            return self.http_not_found()

        # Render the template with data and write it to the HTTP response.
        self.response.write(template.render(kwargs))
Exemplo n.º 15
0
    def get(self, *args, **kwargs):

        self.write('dist/neptune.html',
                   is_localhost=util.is_localhost(),
                   sentry_url=os.environ.get('SENTRY_URL', None),
                   triton_domain=os.environ.get('TRITON_DOMAIN', None),
                   include_profiler=os.environ.get('INCLUDE_PROFILER',
                                                   None) == 'true',
                   profiler_includes=gae_mini_profiler.templatetags.
                   profiler_includes())
Exemplo n.º 16
0
    def http_not_found(self, **kwargs):
        """Respond with a 404.

        Example use:

        class Foo(ViewHandler):
            def get(self):
                return self.http_not_found()
        """
        # default parameters that all views get
        user = self.get_current_user()

        # Sets up the google sign in link, used in modal on all pages, which
        # must include a special flag to alert this handler that google
        # credentials are present in the cookie. It should also incorporate any
        # redirect already set in the URL.
        redirect = str(self.request.get('redirect')) or self.request.url
        google_redirect = util.set_query_parameters(redirect,
                                                    google_login='******')
        google_login_url = app_engine_users.create_login_url(google_redirect)

        kwargs['user'] = user
        kwargs['google_login_url'] = google_login_url
        kwargs['hosting_domain'] = os.environ['HOSTING_DOMAIN']
        kwargs['share_url'] = self.request.url
        kwargs['google_client_id'] = config.google_client_id

        # Determine which Facebook app depending on environment
        kwargs['localhost'] = False
        if util.is_localhost():
            kwargs['localhost'] = True

        # Fetch all themes and topics for navigation
        courses = self.api.get('Theme')
        if courses:
            # fetch topics for each theme
            course_topic_ids = [
                id for course in courses for id in course.topics
            ]
            course_topics = self.api.get_by_id(course_topic_ids)
            # associate topics with appropriate courses
            for course in courses:
                course.associate_topics(course_topics)
                # Special case for "Teachers" kit
                if course.name == 'Growth Mindset for Teachers':
                    kwargs['teacher_topics'] = course.topics_list
        kwargs['courses'] = courses

        self.error(404)
        jinja_environment = self.get_jinja_environment()
        template = jinja_environment.get_template('404.html')
        self.response.write(template.render(kwargs))
Exemplo n.º 17
0
def build_reporting_unit(entity):
    """Compose dict describing one unit for which to generate a report."""
    neptune_url_base = '{protocol}://{domain}'.format(
        protocol='http' if util.is_localhost() else 'https',
        domain=('localhost:8888'
                if util.is_localhost() else os.environ['NEPTUNE_DOMAIN']),
    )
    triton_url_base = '{protocol}://{domain}'.format(
        protocol='http' if util.is_localhost() else 'https',
        domain=('localhost:10080'
                if util.is_localhost() else os.environ['HOSTING_DOMAIN']),
    )

    # Assemble the URLs that RServe will need to post back to.
    dataset_url = '{base}/api/datasets?parent_id={parent_id}'.format(
        base=neptune_url_base,
        parent_id=entity.uid,
    )
    report_url = '{base}/api/reports'.format(base=triton_url_base)

    reporting_unit = {
        'id': entity.uid,
        'team_id': None,
        'classroom_id': None,
        'post_url': dataset_url,
        'post_report_url': report_url,
    }
    if DatastoreModel.get_kind(entity) == 'Organization':
        reporting_unit['organization_id'] = entity.uid
    elif DatastoreModel.get_kind(entity) == 'Team':
        reporting_unit['team_id'] = entity.uid
    elif DatastoreModel.get_kind(entity) == 'Classroom':
        # This kind of report needs two ids because it reports on two levels
        # at once. Classroom data is present in the context of team data.
        reporting_unit['team_id'] = entity.team_id
        reporting_unit['classroom_id'] = entity.uid
    return reporting_unit
Exemplo n.º 18
0
    def setUp(self):
        """Sets self.testbed and activates it, among other global settings.

        This function (noticeably not named with PERTS-standard underscore
        case) is automatically called when starting a test by the unittest
        module. We use it for basic configuration and delegate further set
        up to the more canonically named set_up() of inheriting classes.
        """
        if not util.is_localhost():
            # Logging test activity in production causes errors. This
            # suppresses all logs of level critical and lower, which means all
            # of them. See
            # https://docs.python.org/2/library/logging.html#logging.disable
            logging.disable(logging.CRITICAL)

        # Use the same namespace our test apps will use
        # i.e. webapp2.WSGIApplication
        if os.environ['NAMESPACE']:
            namespace_manager.set_namespace(os.environ['NAMESPACE'])

        # Start a clean testing environment for one test.
        self.testbed = testbed.Testbed()
        self.testbed.activate()

        # Stubs for services we use throughout.
        self.testbed.init_memcache_stub()
        self.testbed.init_taskqueue_stub()
        self.testbed.init_app_identity_stub()
        self.testbed.init_urlfetch_stub()
        self.testbed.init_blobstore_stub()

        # NDB has lots of fancy caching features, whic are normally great, but
        # get in the way of testing consistency.
        # https://cloud.google.com/appengine/docs/python/ndb/cache
        ndb_context = ndb.get_context()
        ndb_context.set_cache_policy(lambda x: False)
        ndb_context.set_memcache_policy(lambda x: False)

        # for simulating google users
        self.testbed.init_user_stub()

        # Allow code to detect whether or not it's running in a unit test.
        self.testbed.setup_env(currently_testing='true', overwrite=True)

        # Let inheriting classes to their own set up.
        if hasattr(self, 'set_up'):
            self.set_up()
Exemplo n.º 19
0
    def get(self):
        self.log_out()

        redirect = self.request.get('redirect') or '/'

        if util.is_localhost():
            # In the SDK, it makes sense to log the current user out of Google
            # entirely (otherwise admins have to click logout twice, b/c
            # existing code will attempt to sign them right in again).
            self.redirect(app_engine_users.create_logout_url(redirect))
        else:
            # In production, we don't want to sign users out of their Google
            # account entirely, because that would break their gmail, youtube,
            # etc. etc. Instead, just clear the cookies on *this* domain that
            # Google creates. That's what self.log_out() does above. So we're
            # done, except for a simple redirect.
            self.redirect(redirect)
Exemplo n.º 20
0
def mandrill_send(template_data={}, **kwargs):

    # Determine if message should send
    if util.is_development() and not config.should_deliver_smtp_dev:
        logging.info('Email not sent, check config!')
        return None

    subject = render(kwargs['subject'], **template_data)

    # Add in default template data
    template_data['to_address'] = kwargs.get('to_address', None)
    template_data['domain'] = util.get_domain()
    # Python keeps time to the microsecond, but we don't need it, and
    # it's easier to render as ISO 8601 without it.
    template_data['server_time'] = datetime.datetime.today().replace(microsecond=0)
    template_data['contact_email_address'] = config.from_server_email_address

    # Determine if using html string or a template
    html_body = None
    if 'html' in kwargs:
        html_body = kwargs['html']
    elif 'body' in kwargs:
        html_body = render(kwargs['body'], **template_data)
    elif 'template' in kwargs:
        html_body = render_template(kwargs['template'], **template_data)

    text_body = kwargs.get('text', None)

    if util.is_localhost() or util.is_testing():
        sender = _send_localhost_and_testing
    elif util.is_development():
        sender = _send_development
    else:
        sender = _send_production

    optional_mandrill_keys = ('from_address', 'reply_to', 'from_name')
    optional_mandrill_kwargs = {k: kwargs[k] for k in optional_mandrill_keys
                                if k in kwargs}

    return sender(kwargs['to_address'], subject, html_body, text_body,
                  kwargs.get('mandrill_template', None),
                  kwargs.get('mandrill_template_content', None),
                  kwargs.get('cc_address', None),
                  kwargs.get('bcc_address', None),
                  **optional_mandrill_kwargs)
Exemplo n.º 21
0
def participation_query_url(cycle, classrooms):
    if util.is_localhost():
        protocol = 'http'
        neptune_domain = 'localhost:8080'
    else:
        protocol = 'https'
        neptune_domain = os.environ['NEPTUNE_DOMAIN']

    url = '{protocol}://{domain}/api/project_cohorts/participation'.format(
        protocol=protocol,
        domain=neptune_domain,
    )
    return util.set_query_parameters(
        url,
        uid=[c.url_code for c in classrooms],
        start=cycle.start_date.strftime(config.iso_datetime_format),
        end=cycle.end_date.strftime(config.iso_datetime_format),
    )
Exemplo n.º 22
0
 def get(self, *args):
     if util.is_localhost():
         neptune_protocol = 'http'
         neptune_domain = 'localhost:8080'
         triton_protocol = 'http'
         triton_domain = 'localhost:10080'
     else:
         neptune_protocol = 'https'
         neptune_domain = os.environ['NEPTUNE_DOMAIN']
         triton_protocol = 'https'
         triton_domain = os.environ['HOSTING_DOMAIN']
     self.write(
         'index.html',
         neptune_protocol=neptune_protocol,
         neptune_domain=neptune_domain,
         triton_protocol=triton_protocol,
         triton_domain=triton_domain,
         sentry_config_url=os.environ['SENTRY_CONFIG_URL'],
     )
Exemplo n.º 23
0
    def get_participation_for_cycle(self, classrooms, cycle):
        if not cycle.start_date or not cycle.end_date:
            return {}

        handler = TeamsClassrooms()
        user = User.create(id='triton', email='')
        jwt = handler.classroom_participation_jwt(user, classrooms)

        if util.is_localhost():
            protocol = 'http'
            neptune_domain = 'localhost:8080'
        else:
            protocol = 'https'
            neptune_domain = os.environ['NEPTUNE_DOMAIN']

        start_datetime = datetime.datetime.combine(
            cycle.start_date, datetime.datetime.min.time())
        end_datetime = datetime.datetime.combine(cycle.end_date,
                                                 datetime.datetime.max.time())
        url = (
            '{protocol}://{domain}/api/project_cohorts/participation?{ids}&start={start_date}&end={end_date}'
            .format(
                protocol=protocol,
                domain=neptune_domain,
                ids='&'.join(['uid={}'.format(c.url_code)
                              for c in classrooms]),
                start_date=util.datelike_to_iso_string(start_datetime),
                end_date=util.datelike_to_iso_string(end_datetime),
            ))

        result = urlfetch.fetch(
            url=url,
            method=urlfetch.GET,
            headers={'Authorization': 'Bearer {}'.format(jwt)})

        if not result or result.status_code != 200:
            raise Exception("Failed to get participation {}".format(result))

        return json.loads(result.content)
Exemplo n.º 24
0
    def connect_to_db(self):
        """Establish connection to MySQL db instance.

        Either Google Cloud SQL or local MySQL server. Detects environment with
        functions from util module.
        """
        if util.is_localhost() or util.is_codeship():
            credentials = {
                'host': self.local_ip,
                'port': self.local_port,
                'user': self.local_user,
                'passwd': self.local_password
            }
        else:
            # Note: for second generation cloud sql instances, the instance
            # name must include the region, e.g. 'us-central1:production-01'.
            credentials = {
                'unix_socket':
                '/cloudsql/{app_id}:{instance_name}'.format(
                    app_id=app_identity.get_application_id(),
                    instance_name=self.cloud_sql_instance),
                'user':
                self.cloud_sql_user,
            }
        if self.db_name:
            credentials['db'] = self.db_name

        # Although the docs say you can specify a `cursorclass` keyword
        # here as an easy way to get dictionaries out instead of lists, that
        # only works in version 1.2.5, and App Engine only has 1.2.4b4
        # installed as of 2015-03-30. Don't use it unless you know the
        # production library has been updated.
        # tl;dr: the following not allowed!
        # self.connection = MySQLdb.connect(
        #     charset='utf8', cursorclass=MySQLdb.cursors.DictCursor, **creds)
        self.connection = MySQLdb.connect(charset='utf8', **credentials)
        self.cursor = self.connection.cursor()
Exemplo n.º 25
0
    def connect_to_db(self):
        """Establish connection to MySQL db instance.

        Either Google Cloud SQL or local MySQL server. Detects environment with
        functions from util module.
        """
        if util.is_localhost():
            env_type = 'localhost'
        elif util.is_development():
            env_type = 'development'
        else:
            env_type = 'production'

        creds = self.credentials[env_type]

        # Although the docs say you can specify a `cursorclass` keyword
        # here as an easy way to get dictionaries out instead of lists, that
        # only works in version 1.2.5, and App Engine only has 1.2.4b4
        # installed as of 2015-03-30. Don't use it unless you know the
        # production library has been updated.
        # tl;dr: the following not allowed!
        # self.connection = MySQLdb.connect(
        #     charset='utf8', cursorclass=MySQLdb.cursors.DictCursor, **creds)
        self.connection = MySQLdb.connect(charset='utf8', **creds)
Exemplo n.º 26
0
def get_params():
    """Get MySQL db connection for any environment."""

    if util.is_localhost():
        if util.is_testing():
            # testing on localhost
            params = {
                'db_name': os.environ['LOCAL_SQL_TEST_DB_NAME'],
                'local_user': os.environ['LOCAL_SQL_USER'],
                'local_password': os.environ['LOCAL_SQL_PASSWORD'],
            }
        else:
            # normal app running on localhost
            params = {
                'db_name': os.environ['LOCAL_SQL_DB_NAME'],
                'local_user': os.environ['LOCAL_SQL_USER'],
                'local_password': os.environ['LOCAL_SQL_PASSWORD'],
            }
    elif util.is_codeship():
        # testing on codeship
        params = {
            # These are set up for us by codeship.
            # https://documentation.codeship.com/databases/mysql/
            'db_name': 'test',
            'local_user': os.environ['MYSQL_USER'],
            'local_password': os.environ['MYSQL_PASSWORD'],
        }
    else:
        # Deployed, either on the dev app or the production app
        params = {
            'db_name': os.environ['CLOUD_SQL_DB_NAME'],
            'cloud_sql_instance': os.environ['CLOUD_SQL_INSTANCE_ID'],
            'cloud_sql_user': '******',
        }

    return params
Exemplo n.º 27
0
    def setUp(self):
        """Sets self.testbed and activates it, among other global settings.

        This function (noticeably not named with PERTS-standard undrescore
        case) is automatically called when starting a test by the unittest
        module. We use it for basic configuration and delegate further set
        up to the more canonically named set_up() of inheriting classes.
        """
        if not util.is_localhost():
            # Logging test activity in production causes errors. This
            # suppresses all logs of level critical and lower, which means all
            # of them. See
            # https://docs.python.org/2/library/logging.html#logging.disable
            logging.disable(logging.CRITICAL)

        # Start a clean testing environment for one test.
        self.testbed = testbed.Testbed()
        self.testbed.activate()

        # user services
        self.testbed.init_user_stub()

        # Writing students involves tasks and memcache, so we need stubs for
        # those.
        self.testbed.init_memcache_stub()
        self.testbed.init_taskqueue_stub(root_path='.')
        self.taskqueue_stub = self.testbed.get_stub(
            testbed.TASKQUEUE_SERVICE_NAME)

        # Basic apis not related to specific users.
        self.public_api = Api(User(user_type='public'))
        self.internal_api = Api(User(user_type='god'))

        # Let inheriting classes to their own set up.
        if hasattr(self, 'set_up'):
            self.set_up()
Exemplo n.º 28
0
 def delete_everything(self):
     if not (self.user and self.user.is_admin and util.is_localhost()):
         raise PermissionDenied("Only admins working on a localhost "
                                "server can delete everything.")
     util.delete_everything()
     util.delete_all_in_index(config.content_index)
Exemplo n.º 29
0
    def dispatch(self):
        """Wraps the other request handlers.

        * Manages sessions
        * Manages request profiling
        """
        util.profiler.add_event("BaseHandler.dispatch()")

        # ** Code to run before all handlers goes here. ** #

        # The App Engine runtime does weird caching of classes and class
        # properties such that you can't expect them to be cleanly segregated
        # or reset between requests. But we want to use this property to avoid
        # multiple lookups of the same user within a request. So make sure it
        # has a clean start.
        # https://cloud.google.com/appengine/docs/standard/python/how-requests-are-handled#app-caching
        self._user = None

        if util.is_localhost():
            # ports are arbitrary, but convenient
            os.environ['YELLOWSTONE_DOMAIN'] = 'localhost:9080'
            os.environ['YELLOWSTONE_PROTOCOL'] = 'http'
            os.environ['NEPTUNE_DOMAIN'] = 'localhost:8080'
            os.environ['NEPTUNE_PROTOCOL'] = 'http'
            os.environ['TRITON_DOMAIN'] = 'localhost:10080'
            os.environ['TRITON_PROTOCOL'] = 'http'
        else:
            # Various DOMAINs remain set as in app.yaml
            os.environ['YELLOWSTONE_PROTOCOL'] = 'https'
            os.environ['NEPTUNE_PROTOCOL'] = 'https'
            os.environ['TRITON_PROTOCOL'] = 'https'

        # Set the namespace, which varies by branch.
        namespace = os.environ['NAMESPACE']
        if namespace:
            logging.info("Setting namespace: {}".format(namespace))
            namespace_manager.set_namespace(namespace)

        # Newly deployed dev branches might not have a database in their
        # namespace yet.
        self.init_database()

        if self.using_sessions():
            # Get a session store for this request.
            self.session_store = sessions.get_store(request=self.request)

        # Allow load testing services to log in quickly.
        if util.is_development() and self.request.get('demo_login',
                                                      None) == 'wamxdkrwnkgey':
            user = User.get_by_id('User_demo')
            self.log_in(user)
            self.redirect(self.request.path)

        # Handler classes may set a class property `requires_auth` which triggers a check
        # for an authenticated user. If there isn't one, the request is immediately
        # rejeted with a 401. This does not apply to preflight OPTIONS calls which never
        # include Authorization headers (they're about figuring out the server's CORS
        # rules, not taking any actions).
        authed = getattr(self, 'requires_auth', False)
        options = self.request.method == 'OPTIONS'

        # This may be used by downstream handlers to override permissions if
        # necessary.
        self.allowed_by_jwt = self.jwt_allows_endpoint(self.get_endpoint_str())
        if self.allowed_by_jwt:
            logging.info("BaseHandler: this request is ALLOWED by the jwt.")

        if authed and not options:
            user = self.get_current_user()
            if user.user_type == 'public' and not self.allowed_by_jwt:
                return self.http_unauthorized()

        try:
            # Call the overridden dispatch(), which has the effect of running
            # the get() or post() etc. of the inheriting class.
            webapp2.RequestHandler.dispatch(self)

        finally:
            # ** Code to run after all handlers goes here. ** #

            if self.using_sessions():
                # Save all sessions.
                self.session_store.save_sessions(self.response)

            util.profiler.add_event("END")

            # Turn on for debugging/profiling.
            # logging.info(util.profiler)

            util.profiler.clear()
Exemplo n.º 30
0
from model import SecretValue
from task_handlers import task_routes
from view_handlers import view_routes
import config
import logging
import util


# Attempt to look up the encryption key used to protect our session cookies.
# In normal operation there should be one stored in a SecretValue entity. If
# we can't find it, fill in a default value, but log an error to bother the
# devs.
sv_entity = SecretValue.get_by_id('session_cookie_secret_key')
if sv_entity is None:
    secret_key = config.default_session_cookie_secret_key
    if not util.is_localhost():
        logging.error("No SecretValue set for 'session_cookie_secret_key'.")
else:
    # Why the string coercion? If the value here is a unicode, app
    # engine complains, "TypeError: character mapping must return
    # integer, None or unicode"
    secret_key = str(sv_entity.value)

webapp2_config = {
    'webapp2_extras.sessions': {
        # Related to cookie security, see:
        # http://webapp-improved.appspot.com/api/webapp2_extras/sessions.html
        'secret_key': secret_key
    },
}
Exemplo n.º 31
0
    def write(self, template_filename, template_path='templates', **kwargs):
        util.profiler.add_event("Begin ViewHandler:write")
        jinja_environment = self.get_jinja_environment(template_path)

        # Jinja environment filters:

        @jinja2.evalcontextfilter
        def jinja_json_filter(eval_context, value):
            """Seralize value as JSON and mark as safe for jinja."""
            return jinja2.Markup(json.dumps(value))

        jinja_environment.filters['to_json'] = jinja_json_filter

        def nl2br(value):
            """Replace new lines with <br> for html view"""
            return value.replace('\n', '<br>\n')

        jinja_environment.filters['nl2br'] = nl2br

        def format_datetime(value):
            # Formats datetime as Ex: "January 9, 2015"
            return '{dt:%B} {dt.day}, {dt.year}'.format(dt=value)

        jinja_environment.filters['datetime'] = format_datetime

        def format_ampescape(value):
            return value.replace('&', '%26')

        jinja_environment.filters['ampescape'] = format_ampescape

        def format_filetype(value):
            if value.split('/')[0] in ['application']:
                if value.split('/')[1] in ['pdf']:
                    formatted_type = 'pdf file'
                elif value.split('/')[1].find('wordprocessing') > -1:
                    formatted_type = 'word document'
                elif value.split('/')[1].find('presentation') > -1:
                    formatted_type = 'presentation'
                else:
                    formatted_type = 'document'
            elif value.split('/')[0] in ['image']:
                formatted_type = 'image file'
            else:
                formatted_type = value.split('/')[0]
            return formatted_type

        jinja_environment.filters['filetype'] = format_filetype

        util.profiler.add_event("Begin ViewHandler:add_jinja_filters")

        user = self.get_current_user()

        util.profiler.add_event("Begin ViewHandler:get_current_user()")

        # Only get sign in links if no user is present
        if user is None:
            # Sets up the google sign in link, used in modal on all pages,
            # which must include a special flag to alert this handler that
            # google credentials are present in the cookie. It should also
            # incorporate any redirect already set in the URL.
            redirect = str(self.request.get('redirect')) or self.request.url
            google_redirect = util.set_query_parameters(redirect,
                                                        google_login='******')
            google_login_url = app_engine_users.create_login_url(
                google_redirect)
        else:
            google_login_url = ''

        util.profiler.add_event("Begin ViewHandler:get_login_redirects")

        # default parameters that all views get
        kwargs['user'] = user
        kwargs['google_login_url'] = google_login_url
        kwargs['hosting_domain'] = os.environ['HOSTING_DOMAIN']
        kwargs['share_url'] = self.request.url
        kwargs['google_client_id'] = config.google_client_id

        util.profiler.add_event("Begin ViewHandler:set_user_params")

        # Determine which Facebook app depending on environment
        kwargs['localhost'] = False
        if util.is_localhost():
            kwargs['localhost'] = True

        util.profiler.add_event("Begin ViewHandler:start_fetching_themes")

        # Fetch all themes and topics for navigation
        courses = self.api.get('Theme')
        if courses:
            # Fetch all topics for courses
            course_topic_ids = [
                id for course in courses for id in course.topics
            ]
            course_topics = self.api.get_by_id(course_topic_ids)
            # Associate topics with appropriate courses
            for course in courses:
                course.associate_topics(course_topics)
                # Special case for "Teachers" kit
                if course.name == 'Growth Mindset for Teachers':
                    # IDK WHAT THIS IS
                    kwargs['teacher_topics'] = course.topics_list
        kwargs['courses'] = courses

        util.profiler.add_event("Begin ViewHandler:finish_fetching_themes")

        logging.info(util.profiler)

        # Try to load the requested template. If it doesn't exist, replace
        # it with a 404.
        try:
            template = jinja_environment.get_template(template_filename)
        except jinja2.exceptions.TemplateNotFound:
            logging.error("TemplateNotFound: {}".format(template_filename))
            return self.http_not_found()

        # logging.info('kwargs={}', kwargs['book'])

        # Render the template with data and write it to the HTTP response.
        self.response.write(template.render(kwargs))