hack4impact/maps4all

View on GitHub
app/main/views.py

Summary

Maintainability
D
2 days
Test Coverage
import json
import os
from twilio.rest.lookups import TwilioLookupsClient
from twilio.rest import TwilioRestClient
from flask import render_template, url_for, request, jsonify, make_response
from flask.ext.login import login_required
from twilio import twiml
from app import csrf
from .. import db
from ..models import EditableHTML, Resource, Rating, Descriptor, OptionAssociation, RequiredOptionDescriptor, SiteAttribute
from . import main
from wtforms.fields import SelectMultipleField, TextAreaField
from ..single_resource.forms import SingleResourceForm
from datetime import datetime


@main.route('/')
def index():
    # set descriptors
    req_opt_desc = RequiredOptionDescriptor.query.all()
    req_opt_id = -1
    if req_opt_desc:
        req_opt_desc = req_opt_desc[0]
        req_opt_desc = Descriptor.query.filter_by(
            id=req_opt_desc.descriptor_id
        ).first()
        if req_opt_desc is not None:
            req_opt_id = req_opt_desc.id
    options = Descriptor.query.all()
    options = [o for o in options if o.dtype == 'option' and o.id != req_opt_id]
    options_dict = {}
    for o in options:
        options_dict[o.name] = o.values
    req_options = {}
    if req_opt_desc:
        for val in req_opt_desc.values:
            req_options[val] = False
    # check if admin has set twilio authentication
    twilio_auth = not SiteAttribute.get_value(
        'TWILIO_AUTH_TOKEN') and not SiteAttribute.get_value('TWILIO_ACCOUNT_SID')
    # modal attributes
    attributes = [
        'WELCOME_HEADER',
        'WELCOME_CONTENT',
        'WELCOME_ACTION',
        'WELCOME_FOOTER',
        'WELCOME_WEBSITE_TEXT',
        'WELCOME_WEBSITE_URL',
        'WELCOME_EMAIL',
        'WELCOME_FACEBOOK_URL',
        'WELCOME_TWITTER_URL',
        'WELCOME_INSTAGRAM_URL',
        'WELCOME_YOUTUBE_URL',
    ]
    modal_attributes = {}
    for attr in attributes:
        modal_attributes[attr] = SiteAttribute.get_value(attr) or ''
    # check for first-time user to render welcome modal to
    print(request.cookies.get('first_time_user'))
    show_modal = request.cookies.get(
        'first_time_user') != 'False' and SiteAttribute.get_value('HAS_WELCOME_MODAL') == 'Yes'
    resp = make_response(render_template('main/index.html',
                                         options=options_dict,
                                         req_options=req_options,
                                         req_desc=req_opt_desc,
                                         twilio_auth=twilio_auth,
                                         show_modal=show_modal,
                                         modal=modal_attributes))
    resp.set_cookie('first_time_user', 'False')
    return resp


@main.route('/get-resources')
def get_resources():
    resources = Resource.query.all()
    resources_as_dicts = Resource.get_resources_as_dicts(resources)
    return json.dumps(resources_as_dicts)


@main.route('/search-resources')
def search_resources():
    name = request.args.get('name')
    if name is None:
        name = ""
    req_options = request.args.getlist('reqoption')
    if req_options is None:
        req_options = []
    # case insensitive search
    resource_pool = Resource.query.filter(
        Resource.name.ilike('%{}%'.format(name))).all()
    req_opt_desc = RequiredOptionDescriptor.query.all()
    if req_opt_desc:
        req_opt_desc = req_opt_desc[0]
        req_opt_desc = Descriptor.query.filter_by(
            id=req_opt_desc.descriptor_id
        ).first()
    resources = []
    if req_opt_desc and len(req_options) > 0:
        int_req_options = []
        for o in req_options:
            int_req_options.append(req_opt_desc.values.index(str(o)))
        for resource in resource_pool:
            associations = OptionAssociation.query.filter_by(
                resource_id=resource.id,
                descriptor_id=req_opt_desc.id
            )
            for a in associations:
                if a.option in int_req_options:
                    resources.append(resource)
                    break
    opt_options = request.args.getlist('optoption')
    option_map = {}
    # Create a dict, option_map, that maps from option names to a list of user selected values
    for opt in opt_options:
        if opt != "null":
            option_val = opt.split(',')
            for opt_val in option_val:
                key_val = opt_val.split(':')
                if key_val[0] in option_map:
                    option_map[key_val[0]].append(key_val[1])
                else:
                    option_map[key_val[0]] = [key_val[1]]

    descriptors = Descriptor.query.all()
    new_pool = resource_pool
    if len(req_options) > 0:
        new_pool = resources
        resources = []
    # Iterate through resources and check that there's a match for all of the options
    # that the user selected. If there is, add that resource to the list of resources
    for resource in new_pool:
        number_of_options_found = 0
        for opt in list(option_map.keys()):
            opt_descriptors = OptionAssociation.query.filter_by(
                resource_id=resource.id
            )
            for desc in opt_descriptors:
                if desc.descriptor.name == opt:
                    if desc.descriptor.values[desc.option] in option_map[opt]:
                        number_of_options_found += 1
                        break
        if number_of_options_found == len(list(option_map.keys())):
            resources.append(resource)
    resources_as_dicts = Resource.get_resources_as_dicts(resources)
    return json.dumps(resources_as_dicts)


@main.route('/get-associations/<int:resource_id>')
def get_associations(resource_id):
    resource = Resource.query.get(resource_id)
    associations = {} # map from descriptor name -> {descriptor value(s), descriptor type}
    if resource is None:
        return json.dumps(associations)
    for hd in resource.hyperlink_descriptors:
        associations[hd.descriptor.name] = {'value': hd.url, 'type': 'Hyperlink'}
    for td in resource.text_descriptors:
        associations[td.descriptor.name] = {'value': td.text, 'type': 'Text'}
    for od in resource.option_descriptors:
        val = od.descriptor.values[od.option]
        if associations.get(od.descriptor.name):
            od_association = associations.get(od.descriptor.name)
            od_association['value'].append(val)
        else:
            associations[od.descriptor.name] = {'value': [val], 'type': 'Option'}
    return json.dumps(associations)


@main.route('/pages/<pageName>')
def render_page(pageName):
    editable_html_obj = EditableHTML.get_editable_html(pageName)
    return render_template('main/generalized_page.html',
                           editable=editable_html_obj)


@main.route('/about')
def about():
    editable_html_obj = EditableHTML.get_editable_html('about')
    if editable_html_obj is False:
        edit = EditableHTML(editor_name='about', page_name='About', value='')
        db.session.add(edit)
        db.session.commit()
        editable_html_obj = edit
    return render_template('main/about.html',
                           editable_html_obj=editable_html_obj)


@main.route('/overview')
@login_required
def overview():
    editable_html_obj = EditableHTML.get_editable_html('overview')
    if editable_html_obj is False:
        edit = EditableHTML(editor_name='overview',
                            page_name='Overview', value='')
        db.session.add(edit)
        db.session.commit()
        editable_html_obj = edit
    return render_template('main/overview.html',
                           editable_html_obj=editable_html_obj)


@main.route('/update-editor-contents', methods=['POST'])
@login_required
def update_editor_contents():
    """Update the contents of an editor."""
    edit_data = request.form.get('edit_data')
    editor_name = request.form.get('editor_name')
    editor_contents = EditableHTML.query.filter_by(
        editor_name=editor_name).first()
    if editor_contents is None:
        editor_contents = EditableHTML(editor_name=editor_name)
    editor_contents.value = edit_data
    db.session.add(editor_contents)
    db.session.commit()
    return 'OK', 200


@csrf.exempt
@main.route('/send-sms', methods=['POST'])
def send_sms():
    sid = os.environ.get('TWILIO_ACCOUNT_SID')
    auth = os.environ.get('TWILIO_AUTH_TOKEN')
    client = TwilioLookupsClient(account=sid, token=auth)
    send_client = TwilioRestClient(account=sid, token=auth)
    if request is not None:
        phone_num = request.json['number']
        resourceID = request.json['id']
        curr_res = Resource.query.get(resourceID)
        name = "Name: " + curr_res.name
        address = "Address: " + curr_res.address
        message = name + "\n" + address
        try:
            number = client.phone_numbers.get(
                phone_num, include_carrier_info=False)
            num = number.phone_number
            send_client.messages.create(
                to=num,
                from_="+17657692023",
                body=message)
            return jsonify(status='success')
        except:
            return jsonify(status='error')


@csrf.exempt
@main.route('/rating-post', methods=['POST'])
def post_rating():
    if request is not None:
        time = datetime.now()
        star_rating = request.json['rating']
        comment = request.json['review']
        resourceID = request.json['id']
        if comment and star_rating:
            rating = Rating(submission_time=time,
                            rating=star_rating,
                            review=comment,
                            resource_id=resourceID)
            db.session.add(rating)
            db.session.commit()
        elif star_rating:
            rating = Rating(submission_time=time,
                            rating=star_rating,
                            resource_id=resourceID)
            db.session.add(rating)
            db.session.commit()
    return jsonify(status='success')