<commit_before>#!/usr/bin/env python

from __future__ import print_function
from future.standard_library import install_aliases
install_aliases()

from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError

import json
import os

import re #retira etiquetas HTML de la descripción

from flask import Flask
from flask import request
from flask import make_response

# Flask app should start in global layout
app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print("Request:")
    print(json.dumps(req, indent=4))

    res = makeWebhookResult(req)#Invoca función de consulta y muestra speech al situr3

    res = json.dumps(res, indent=4)
    print(res)
    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'
    return r

def makeWebhookResult(req):
    if req.get("result").get("action") != "buscarAtractivos":
        return {}
    result = req.get("result")#invocar el result del json
    parameters = result.get("parameters")#invocar el parameters dentro de result
    atractivos = parameters.get("atractivos")#DATO TRAÍDO DE API.AI - ATRACTIVOS

    #URL BASE CONSULTA ATRACTIVOS JSON
    baseUrlAtractivos = "http://situr.boyaca.gov.co/wp-json/wp/v2/atractivo_turistico?offset=0&search="#URL Base Atractivos
    baseUrlImgAtract = "http://www.situr.boyaca.gov.co/wp-json/wp/v2/media/"#URL Base Imagenes Atractivos
    retirarEspacios = atractivos.replace(" ",  "%20")#Retirar Espacios Atractivos

    leerAtractivo = json.loads(urlopen(baseUrlAtractivos + retirarEspacios).read())
    tituloAtractivo = leerAtractivo[0]['title']['rendered']
    descripcionAtractivo = re.sub("<.*?>", "", leerAtractivo[0]['excerpt']['rendered'])
    urlAtractivo = leerAtractivo[0].get('link')
    idImagenAtractivo = str(leerAtractivo[0]['featured_media'])

    leerImagenAtr = json.loads(urlopen(baseUrlImgAtract + idImagenAtractivo).read())
    imagenAtractivo = leerImagenAtr['media_details']['sizes']['medium']['source_url']

    speech = "El atractivo: " + tituloAtractivo + ". Descripción:" + descripcionAtractivo + "    y la url de la imagen es: " + imagenAtractivo

    print("Response:")
    print(speech)

    return {
        "speech": speech,
        "displayText": speech,
        "data" : {
            "facebook" : {
              "attachment": {
                "type": "template",
                "payload": {
                  "template_type": "list",
                  "top_element_style": "compact",
                  "elements": [
                    {
                      "title": tituloAtractivo,
                      "image_url": imagenAtractivo,
                      "subtitle": descripcionAtractivo,
                      "buttons": [
                        {
                          "title": 'title',
                          "type": 'web_url',
                          "url": 'http://www.google.com.au',
                          "webview_height_ratio": 'compact'
                        }
                      ]
                    },
                    {
                      "title": 'title',
                      "image_url": null,
                      "subtitle": 'subtitle subtitle subtitle',
                      "buttons": [
                        {
                          "title": 'title',
                          "type": 'web_url',
                          "url": 'http://www.google.com.au',
                          "webview_height_ratio": 'compact'
                        }
                      ]
                    }
                  ]
                }
              }
            }
        },
 #       "contextOut": [{"name":"desdepython", "lifespan":2, "parameters":{"slug":urlAtractivo}}],
        "source": "apiai-situr3"
    }

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print("Starting app on port %d" % port)

    app.run(debug=False, port=port, host='0.0.0.0')
<commit_msg>Original<commit_after>#!/usr/bin/env python

from __future__ import print_function
from future.standard_library import install_aliases
install_aliases()

from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError

import json
import os

import re #retira etiquetas HTML de la descripción

from flask import Flask
from flask import request
from flask import make_response

# Flask app should start in global layout
app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print("Request:")
    print(json.dumps(req, indent=4))

    res = makeWebhookResult(req)#Invoca función de consulta y muestra speech al situr3

    res = json.dumps(res, indent=4)
    print(res)
    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'
    return r

def makeWebhookResult(req):
    if req.get("result").get("action") != "buscarAtractivos":
        return {}
    result = req.get("result")#invocar el result del json
    parameters = result.get("parameters")#invocar el parameters dentro de result
    atractivos = parameters.get("atractivos")#DATO TRAÍDO DE API.AI - ATRACTIVOS

    #URL BASE CONSULTA ATRACTIVOS JSON
    baseUrlAtractivos = "http://situr.boyaca.gov.co/wp-json/wp/v2/atractivo_turistico?offset=0&search="#URL Base Atractivos
    baseUrlImgAtract = "http://www.situr.boyaca.gov.co/wp-json/wp/v2/media/"#URL Base Imagenes Atractivos
    retirarEspacios = atractivos.replace(" ",  "%20")#Retirar Espacios Atractivos

    leerAtractivo = json.loads(urlopen(baseUrlAtractivos + retirarEspacios).read())
    tituloAtractivo = leerAtractivo[0]['title']['rendered']
    descripcionAtractivo = re.sub("<.*?>", "", leerAtractivo[0]['excerpt']['rendered'])
    urlAtractivo = leerAtractivo[0].get('link')
    idImagenAtractivo = str(leerAtractivo[0]['featured_media'])

    leerImagenAtr = json.loads(urlopen(baseUrlImgAtract + idImagenAtractivo).read())
    imagenAtractivo = leerImagenAtr['media_details']['sizes']['medium']['source_url']

    speech = "El atractivo: " + tituloAtractivo + ". Descripción:" + descripcionAtractivo + "    y la url de la imagen es: " + imagenAtractivo

    print("Response:")
    print(speech)

    return {
        "speech": speech,
        "displayText": speech,
        "data" : {
            "facebook" : {
              "attachment": {
                  "attachment" : {
                      "type" : "template",
                      "payload" : {
                          "template_type" : "generic",
                         "elements" : [
                              {
                                  "title" : tituloAtractivo,
                                  "image_url" : imagenAtractivo,
                                  "subtitle": descripcionAtractivo,
                              }
                         ]
                     }
                  }
              }
            }
        },
 #       "contextOut": [{"name":"desdepython", "lifespan":2, "parameters":{"slug":urlAtractivo}}],
        "source": "apiai-situr3"
    }

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print("Starting app on port %d" % port)

    app.run(debug=False, port=port, host='0.0.0.0')
<|endoftext|>


<commit_before>#!/usr/bin/env python

import requests
import urllib
import json
import os
import re

from flask import Flask
from flask import request
from flask import make_response

# Flask app should start in global layout
app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print("Request:")
    print(json.dumps(req, indent=4))

    res = makeWebhookResult(req)

    res = json.dumps(res, indent=4)
    print(res)
    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'
    return r

def makeWebhookResult(req):
    if req.get("result").get("action") == "search.items":
        result = req.get("result")
        parameters = result.get("parameters")
        color = parameters.get("color")
        cat = parameters.get("catalog-category")

        rq = requests.get("http://www.lanebryant.com/lanebryant/search?Ntt=" + color + " " + cat + "&format=JSON")
        jdata = json.loads(rq.text)
        speech = "I found " + str(jdata["contents"][0]["MainContent"][0]["MainContent"][0]["contents"][0]["totalNumRecs"]) + " " + color + " " + cat + " products."
    elif req.get("result").get("action") == "some.else":
        result = req.get("result")
        parameters = result.get("parameters")
        zipcode = parameters.get("zipcode")
        ordernum = parameters.get("order-number")

        rq = requests.get("https://www.shopjustice.com/justice/homepage/includes/order-response-html.jsp?orderNum=" + ordernum + "&billingZip=" + zipcode + "&Action=fetchODDetails")
        #matchObj = re.match( r'.*(.*?)<\/span>.*', rq.text, re.M|re.I)
        matchObj = r.text[r.text.find("mar-status")+12:r.text.find("<", r.text.find("mar-status"))]
        #print rq.text
        status = "Not available"
        if len(matchObj) < 50:
            status = matchObj
            print "matchObj : ", matchObj
        else:
            print "No match!!"
        speech = "Order status is " + status
    else:
        return{}
    print("Response:")
    print(speech)
    return {
        "speech": speech,
        "displayText": speech,
        #"data": {},
        # "contextOut": [],
        "source": "apiai-onlinestore-search"
    }

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print "Starting app on port %d" % port

    app.run(debug=True, port=port, host='0.0.0.0')
<commit_msg>Using split instead of regex<commit_after>#!/usr/bin/env python

import requests
import urllib
import json
import os
import re

from flask import Flask
from flask import request
from flask import make_response

# Flask app should start in global layout
app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print("Request:")
    print(json.dumps(req, indent=4))

    res = makeWebhookResult(req)

    res = json.dumps(res, indent=4)
    print(res)
    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'
    return r

def makeWebhookResult(req):
    if req.get("result").get("action") == "search.items":
        result = req.get("result")
        parameters = result.get("parameters")
        color = parameters.get("color")
        cat = parameters.get("catalog-category")

        rq = requests.get("http://www.lanebryant.com/lanebryant/search?Ntt=" + color + " " + cat + "&format=JSON")
        jdata = json.loads(rq.text)
        speech = "I found " + str(jdata["contents"][0]["MainContent"][0]["MainContent"][0]["contents"][0]["totalNumRecs"]) + " " + color + " " + cat + " products."
    elif req.get("result").get("action") == "some.else":
        result = req.get("result")
        parameters = result.get("parameters")
        zipcode = parameters.get("zipcode")
        ordernum = parameters.get("order-number")

        rq = requests.get("https://www.shopjustice.com/justice/homepage/includes/order-response-html.jsp?orderNum=" + ordernum + "&billingZip=" + zipcode + "&Action=fetchODDetails")
        #matchObj = re.match( r'.*(.*?)<\/span>.*', rq.text, re.M|re.I)
        matchObj = rr.text[rq.text.find("mar-status")+12:rq.text.find("<", rq.text.find("mar-status"))]
        #print rq.text
        #matchObj = re.match( r'.*(.*?)<\/span>.*', rq.text, re.M|re.I)
        matchObj = r.text[r.text.find("mar-status")+12:r.text.find("<", r.text.find("mar-status"))]
        #print rq.text
        status = "Not available"
        if len(matchObj) < 50:
            status = matchObj
            print "matchObj : ", matchObj
        else:
            print "No match!!"
        speech = "Order status is " + status
    else:
        return{}
    print("Response:")
    print(speech)
    return {
        "speech": speech,
        "displayText": speech,
        #"data": {},
        # "contextOut": [],
        "source": "apiai-onlinestore-search"
    }

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print "Starting app on port %d" % port

    app.run(debug=True, port=port, host='0.0.0.0')
<|endoftext|>


<commit_before>#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import discord
import re
import time
from wow import *
from util import *
from settings import *

client = discord.Client()

@client.event
async def on_message(message):
    """Listens for specific user messages."""
    # Current time (Used for cache busting character thumbnails).
    epoch_time = int(time.time())

    # If the author is the bot do nothing.
    if message.author == client.user:
        return

    if message.content.startswith('!armory token'):
        split = split_query(message.content, 'wow_token')
        region = split[0]
        info = await wow_token_price(region)

        # Returns a message to the channel if there's an error fetching.
        if info == 'not_found':
            msg = GOLD_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'connection_error':
            msg = CONNECTION_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'credential_error':
            msg = CREDENTIAL_ERROR.format(message)
            await client.send_message(message.channel, msg)

        else:
            msg = '`The current price of a WoW Token on %s realms is %s gold.` :moneybag:' % (region, info)
            await client.send_message(message.channel, msg)

    if message.content.startswith('!armory pve'):
        split = split_query(message.content, 'pve')

        # Assigns the 3rd index in the split to the region
        region = split[3]

        # Sends the returned data to the character_info function to build a character sheet.
        info = await character_info(split[0], split[1], split[2], region)

        # Returns a message to the channel if there's an error fetching.
        if info == 'not_found':
            msg = NOT_FOUND_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'connection_error':
            msg = CONNECTION_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'credential_error':
            msg = CREDENTIAL_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'unknown_error':
            msg = UNKNOWN_ERROR.format(message)
            await client.send_message(message.channel, msg)

        else:
            # Format the AOTC/CE strings if they exist.
            ud_feat = ''

            if info['ud_feat'] != '':
                ud_feat = '**`%s`**' % (info['ud_feat'])

            if info['bod_feat'] != '':
                bod_feat = '**`%s`**' % (info['bod_feat'])

            msg = discord.Embed(
                title='%s' % (info['name']),
                colour=discord.Colour(info['class_colour']),
                url='%s' % (info['armory']),
                description='%s %s %s %s' % (
                    info['level'], info['faction'], info['spec'], info['class_type']))
            msg.set_thumbnail(
                url='https://render-%s.worldofwarcraft.com/character/%s?_%s' % (
                    region, info['thumb'], epoch_time))
            msg.set_footer(
                text='!armory help | Feedback: https://github.com/JamesIves/discord-wow-armory-bot/issues',
                icon_url='https://raw.githubusercontent.com/JamesIves/discord-wow-armory-bot/master/assets/icon.png')
            msg.add_field(
                name='Character',
                value='**`Name`:** `%s`\n**`Realm`:** `%s (%s)`\n**`Item Level`:** `%s`' % (
                    info['name'], info['realm'], region.upper(), info['ilvl']),
                inline=True)
            msg.add_field(
                name='Keystone Achievements (Season 2)',
                value='**`Conqueror (+10)`:** `%s`\n**`Master (+15)`:** `%s` \n' % (
                    info['keystone_season_conqueror'], info['keystone_season_master']),
                inline=True)
            msg.add_field(
                name='Uldir',
                value='**`Normal`:** `%s/%s`\n**`Heroic`:** `%s/%s`\n**`Mythic`:** `%s/%s`\n%s' % (
                    info['uldir']['normal'], info['uldir']['bosses'],
                    info['uldir']['heroic'], info['uldir']['bosses'],
                    info['uldir']['mythic'], info['uldir']['bosses'],
                    ud_feat),
                inline=True)
            msg.add_field(
                name="Battle of Dazar'alor",
                value='**`Normal`:** `%s/%s`\n**`Heroic`:** `%s/%s`\n**`Mythic`:** `%s/%s`\n%s' % (
                    info['battle_of_dazaralor']['normal'], info['battle_of_dazaralor']['bosses'],
                    info['battle_of_dazaralor']['heroic'], info['battle_of_dazaralor']['bosses'],
                    info['battle_of_dazaralor']['mythic'], info['battle_of_dazaralor']['bosses'],
                    bod_feat),
                inline=True)

            await client.send_message(message.channel, embed=msg)

    # Same as before, except this time it's building data for PVP.
    if message.content.startswith('!armory pvp'):
        split = split_query(message.content, 'pvp')
        region = split[3]
        info = await character_info(split[0], split[1], split[2], split[3])

        if info == 'not_found':
            msg = NOT_FOUND_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'connection_error':
            msg = CONNECTION_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'credential_error':
            msg = CREDENTIAL_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'unknown_error':
            msg = UNKNOWN_ERROR.format(message)
            await client.send_message(message.channel, msg)

        else:
            msg = discord.Embed(
                title='%s' % (info['name']),
                colour=discord.Colour(info['class_colour']),
                url='%s' % (info['armory']),
                description='%s %s %s %s (BFA)' % (
                    info['level'], info['faction'], info['spec'], info['class_type']))
            msg.set_thumbnail(
                url='https://render-%s.worldofwarcraft.com/character/%s?_%s' % (
                    region, info['thumb'], epoch_time))
            msg.set_footer(
                text='!armory help | Feedback: https://github.com/JamesIves/discord-wow-armory-bot/issues',
                icon_url='https://github.com/JamesIves/discord-wow-armory-bot/blob/master/assets/icon.png?raw=true')
            msg.add_field(
                name='Character',
                value='**`Name`:** `%s`\n**`Realm`:** `%s (%s)`\n**`Battlegroup`:** `%s`\n**`Item Level`:** `%s`' % (
                    info['name'], info['realm'], region.upper(), info['battlegroup'], info['ilvl']),
                inline=True)
            msg.add_field(
                name='Arena Achievements',
                value='**`Challenger`:** `%s`\n**`Rival`:** `%s`\n**`Duelist`:** `%s`\n**`Gladiator`:** `%s`' % (
                    info['arena_challenger'], info['arena_rival'],
                    info['arena_duelist'], info['arena_gladiator']),
                inline=True)
            msg.add_field(
                name='RBG Achievements',
                value='**`%s`:** `%s`\n**`%s`:** `%s`\n**`%s`:** `%s`' % (
                    info['rbg_2400_name'], info['rbg_2400'],
                    info['rbg_2000_name'], info['rbg_2000'],
                    info['rbg_1500_name'], info['rbg_1500']),
                inline=True)
            msg.add_field(
                name='Rated 2v2',
                value='**`Rating`:** `%s`' % (
                    info['2v2']),
                inline=True)
            msg.add_field(
                name='Rated 3v3',
                value='**`Rating`:** `%s`' % (
                    info['3v3']),
                inline=True)
            msg.add_field(
                name='Rated Battlegrounds',
                value='**`Rating`:** `%s`' % (
                    info['rbg']),
                inline=True)
            msg.add_field(
                name='Skirmish 2v2',
                value='**`Rating`:** `%s`' % (
                    info['2v2s']),
                inline=True)
            msg.add_field(
                name='Lifetime Honorable Kills',
                value='`%s`' % (
                    info['kills']),
                inline=True)

            await client.send_message(message.channel, embed=msg)

    # Display a list of available commands and a set of credits.
    if message.content.startswith('!armory help'):
        msg = """The following commands can be entered:
            ```
            # Displays a players PVE progression, dungeon kills, keystone achievements, etc.
            !armory pve <name> <realm>
            !armory pve <armory-link>

            # Displays a players PVP progression, arena ratings, honorable kills, etc.
            !armory pvp <name> <realm>
            !armory pvp <armory-link>

            # Displays the WoW token price
            !armory token

            # You can also provide an optional region to each query to display players from other WoW regions outside of the bot default, for example EU, US, etc.
            !armory pve <name> <realm> <region>
            !armory pvp <armory-link> <region>
            !armory token <region>

            ```
            • Bot created by James Ives (https://jamesiv.es)
            • Feedback, Issues and Source: https://github.com/JamesIves/discord-wow-armory-bot/issues
            """

        msg = '%s'.format(message) % re.sub(r'(^[ \t]+|[ \t]+(?=:))', '', msg, flags=re.M)
        await client.send_message(message.channel, msg)

@client.event
async def on_ready():
    if WOW_CLIENT_ID is None or WOW_CLIENT_ID == '' or WOW_CLIENT_SECRET is None or WOW_CLIENT_SECRET == '':
        print('Missing World of Warcraft Client ID/Secret. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
        quit()

    if WOW_REGION is None or WOW_REGION == '':
        print('Missing World of Warcraft player region. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
        quit()

    if LOCALE is None or LOCALE == '':
        print('Missing locale. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
        quit()

    else:
        print('Launch Succesful! The bot is now listening for commands...')

if DISCORD_BOT_TOKEN is None or DISCORD_BOT_TOKEN == '':
    print('Missing Discord bot token. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
    quit()

else:
    client.run(DISCORD_BOT_TOKEN)
<commit_msg>Another quick fix<commit_after>#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import discord
import re
import time
from wow import *
from util import *
from settings import *

client = discord.Client()

@client.event
async def on_message(message):
    """Listens for specific user messages."""
    # Current time (Used for cache busting character thumbnails).
    epoch_time = int(time.time())

    # If the author is the bot do nothing.
    if message.author == client.user:
        return

    if message.content.startswith('!armory token'):
        split = split_query(message.content, 'wow_token')
        region = split[0]
        info = await wow_token_price(region)

        # Returns a message to the channel if there's an error fetching.
        if info == 'not_found':
            msg = GOLD_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'connection_error':
            msg = CONNECTION_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'credential_error':
            msg = CREDENTIAL_ERROR.format(message)
            await client.send_message(message.channel, msg)

        else:
            msg = '`The current price of a WoW Token on %s realms is %s gold.` :moneybag:' % (region, info)
            await client.send_message(message.channel, msg)

    if message.content.startswith('!armory pve'):
        split = split_query(message.content, 'pve')

        # Assigns the 3rd index in the split to the region
        region = split[3]

        # Sends the returned data to the character_info function to build a character sheet.
        info = await character_info(split[0], split[1], split[2], region)

        # Returns a message to the channel if there's an error fetching.
        if info == 'not_found':
            msg = NOT_FOUND_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'connection_error':
            msg = CONNECTION_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'credential_error':
            msg = CREDENTIAL_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'unknown_error':
            msg = UNKNOWN_ERROR.format(message)
            await client.send_message(message.channel, msg)

        else:
            # Format the AOTC/CE strings if they exist.
            ud_feat = ''
            bod_feat = ''

            if info['ud_feat'] != '':
                ud_feat = '**`%s`**' % (info['ud_feat'])

            if info['bod_feat'] != '':
                bod_feat = '**`%s`**' % (info['bod_feat'])

            msg = discord.Embed(
                title='%s' % (info['name']),
                colour=discord.Colour(info['class_colour']),
                url='%s' % (info['armory']),
                description='%s %s %s %s' % (
                    info['level'], info['faction'], info['spec'], info['class_type']))
            msg.set_thumbnail(
                url='https://render-%s.worldofwarcraft.com/character/%s?_%s' % (
                    region, info['thumb'], epoch_time))
            msg.set_footer(
                text='!armory help | Feedback: https://github.com/JamesIves/discord-wow-armory-bot/issues',
                icon_url='https://raw.githubusercontent.com/JamesIves/discord-wow-armory-bot/master/assets/icon.png')
            msg.add_field(
                name='Character',
                value='**`Name`:** `%s`\n**`Realm`:** `%s (%s)`\n**`Item Level`:** `%s`' % (
                    info['name'], info['realm'], region.upper(), info['ilvl']),
                inline=True)
            msg.add_field(
                name='Keystone Achievements (Season 2)',
                value='**`Conqueror (+10)`:** `%s`\n**`Master (+15)`:** `%s` \n' % (
                    info['keystone_season_conqueror'], info['keystone_season_master']),
                inline=True)
            msg.add_field(
                name='Uldir',
                value='**`Normal`:** `%s/%s`\n**`Heroic`:** `%s/%s`\n**`Mythic`:** `%s/%s`\n%s' % (
                    info['uldir']['normal'], info['uldir']['bosses'],
                    info['uldir']['heroic'], info['uldir']['bosses'],
                    info['uldir']['mythic'], info['uldir']['bosses'],
                    ud_feat),
                inline=True)
            msg.add_field(
                name="Battle of Dazar'alor",
                value='**`Normal`:** `%s/%s`\n**`Heroic`:** `%s/%s`\n**`Mythic`:** `%s/%s`\n%s' % (
                    info['battle_of_dazaralor']['normal'], info['battle_of_dazaralor']['bosses'],
                    info['battle_of_dazaralor']['heroic'], info['battle_of_dazaralor']['bosses'],
                    info['battle_of_dazaralor']['mythic'], info['battle_of_dazaralor']['bosses'],
                    bod_feat),
                inline=True)

            await client.send_message(message.channel, embed=msg)

    # Same as before, except this time it's building data for PVP.
    if message.content.startswith('!armory pvp'):
        split = split_query(message.content, 'pvp')
        region = split[3]
        info = await character_info(split[0], split[1], split[2], split[3])

        if info == 'not_found':
            msg = NOT_FOUND_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'connection_error':
            msg = CONNECTION_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'credential_error':
            msg = CREDENTIAL_ERROR.format(message)
            await client.send_message(message.channel, msg)

        elif info == 'unknown_error':
            msg = UNKNOWN_ERROR.format(message)
            await client.send_message(message.channel, msg)

        else:
            msg = discord.Embed(
                title='%s' % (info['name']),
                colour=discord.Colour(info['class_colour']),
                url='%s' % (info['armory']),
                description='%s %s %s %s (BFA)' % (
                    info['level'], info['faction'], info['spec'], info['class_type']))
            msg.set_thumbnail(
                url='https://render-%s.worldofwarcraft.com/character/%s?_%s' % (
                    region, info['thumb'], epoch_time))
            msg.set_footer(
                text='!armory help | Feedback: https://github.com/JamesIves/discord-wow-armory-bot/issues',
                icon_url='https://github.com/JamesIves/discord-wow-armory-bot/blob/master/assets/icon.png?raw=true')
            msg.add_field(
                name='Character',
                value='**`Name`:** `%s`\n**`Realm`:** `%s (%s)`\n**`Battlegroup`:** `%s`\n**`Item Level`:** `%s`' % (
                    info['name'], info['realm'], region.upper(), info['battlegroup'], info['ilvl']),
                inline=True)
            msg.add_field(
                name='Arena Achievements',
                value='**`Challenger`:** `%s`\n**`Rival`:** `%s`\n**`Duelist`:** `%s`\n**`Gladiator`:** `%s`' % (
                    info['arena_challenger'], info['arena_rival'],
                    info['arena_duelist'], info['arena_gladiator']),
                inline=True)
            msg.add_field(
                name='RBG Achievements',
                value='**`%s`:** `%s`\n**`%s`:** `%s`\n**`%s`:** `%s`' % (
                    info['rbg_2400_name'], info['rbg_2400'],
                    info['rbg_2000_name'], info['rbg_2000'],
                    info['rbg_1500_name'], info['rbg_1500']),
                inline=True)
            msg.add_field(
                name='Rated 2v2',
                value='**`Rating`:** `%s`' % (
                    info['2v2']),
                inline=True)
            msg.add_field(
                name='Rated 3v3',
                value='**`Rating`:** `%s`' % (
                    info['3v3']),
                inline=True)
            msg.add_field(
                name='Rated Battlegrounds',
                value='**`Rating`:** `%s`' % (
                    info['rbg']),
                inline=True)
            msg.add_field(
                name='Skirmish 2v2',
                value='**`Rating`:** `%s`' % (
                    info['2v2s']),
                inline=True)
            msg.add_field(
                name='Lifetime Honorable Kills',
                value='`%s`' % (
                    info['kills']),
                inline=True)

            await client.send_message(message.channel, embed=msg)

    # Display a list of available commands and a set of credits.
    if message.content.startswith('!armory help'):
        msg = """The following commands can be entered:
            ```
            # Displays a players PVE progression, dungeon kills, keystone achievements, etc.
            !armory pve <name> <realm>
            !armory pve <armory-link>

            # Displays a players PVP progression, arena ratings, honorable kills, etc.
            !armory pvp <name> <realm>
            !armory pvp <armory-link>

            # Displays the WoW token price
            !armory token

            # You can also provide an optional region to each query to display players from other WoW regions outside of the bot default, for example EU, US, etc.
            !armory pve <name> <realm> <region>
            !armory pvp <armory-link> <region>
            !armory token <region>

            ```
            • Bot created by James Ives (https://jamesiv.es)
            • Feedback, Issues and Source: https://github.com/JamesIves/discord-wow-armory-bot/issues
            """

        msg = '%s'.format(message) % re.sub(r'(^[ \t]+|[ \t]+(?=:))', '', msg, flags=re.M)
        await client.send_message(message.channel, msg)

@client.event
async def on_ready():
    if WOW_CLIENT_ID is None or WOW_CLIENT_ID == '' or WOW_CLIENT_SECRET is None or WOW_CLIENT_SECRET == '':
        print('Missing World of Warcraft Client ID/Secret. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
        quit()

    if WOW_REGION is None or WOW_REGION == '':
        print('Missing World of Warcraft player region. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
        quit()

    if LOCALE is None or LOCALE == '':
        print('Missing locale. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
        quit()

    else:
        print('Launch Succesful! The bot is now listening for commands...')

if DISCORD_BOT_TOKEN is None or DISCORD_BOT_TOKEN == '':
    print('Missing Discord bot token. Please refer to https://github.com/JamesIves/discord-wow-armory-bot#configuration for more details')
    quit()

else:
    client.run(DISCORD_BOT_TOKEN)
<|endoftext|>


<commit_before># Software License Agreement (BSD License)
#
# Copyright (c) 2009-2011, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
# without modification, are permitted provided that the following conditions
# are met:
#
#   Redistributions of source code must retain the above
#   copyright notice, this list of conditions and the
#   following disclaimer.
#
#   Redistributions in binary form must reproduce the above
#   copyright notice, this list of conditions and the
#   following disclaimer in the documentation and/or other
#   materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author: Mitch Garnaat mgarnaat@eucalyptus.com

import urllib, base64
import time
from boto.connection import AWSAuthConnection
from boto import handler
from boto.resultset import ResultSet
from boto.exception import BotoClientError
from boto.exception import S3ResponseError
from boto.exception import S3CreateError
from boto.s3.bucket import Bucket

class EucaConnection(AWSAuthConnection):

    DefaultHost = 'localhost'
    DefaultPort = 8773

    def __init__(self, private_key_path, cert_path,
                 aws_access_key_id=None, aws_secret_access_key=None,
                 is_secure=False, port=DefaultPort, proxy=None, proxy_port=None,
                 proxy_user=None, proxy_pass=None,
                 host=DefaultHost, debug=0, https_connection_factory=None,
                 path='/'):
        self.private_key_path = private_key_path
        self.cert_path = cert_path
        AWSAuthConnection.__init__(self, host, aws_access_key_id,
                                   aws_secret_access_key,
                                   is_secure, port, proxy, proxy_port,
                                   proxy_user, proxy_pass,
                                   debug=debug,
                                   https_connection_factory=https_connection_factory,
                                   path=path)

    def _required_auth_capability(self):
        return ['euca-nc']

    def make_request(self, method='GET', bucket='', key='', headers=None,
                     data='', query_args=None, sender=None,
                     override_num_retries=None, action=None,
                     effective_user_id = None, params=None):
        if headers is None:
            headers = {}
        if params is None:
            params = {}
        if not effective_user_id:
            effective_user_id = self.aws_access_key_id
        if action:
            headers['EucaOperation'] = action
        headers['AWSAccessKeyId'] = effective_user_id
        cert_file = open(self.cert_path, 'r')
        cert_str = cert_file.read()
        cert_file.close()
        headers['EucaCert'] = base64.b64encode(cert_str)
        if not headers.has_key('Content-Length'):
            headers['Content-Length'] = str(len(data))
        if not headers.has_key('Date'):
            headers['Date'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
                                            time.gmtime())
        utf8_params = {}
        for key in params:
            utf8_params[key] = self.get_utf8_value(params[key])
        path_base = '/'
        path_base += "%s/" % bucket
        path = path_base + urllib.quote(key)
        http_request = self.build_base_http_request(method, path, None,
                                                    utf8_params,
                                                    headers, data,
                                                    self.server_name())
        http_request = self.fill_in_auth(http_request,
                                         private_key_path=self.private_key_path)
        return self._send_http_request(http_request, sender)

    def get_bucket(self, bucket_name, validate=True, headers=None):
        bucket = Bucket(self, bucket_name)
        if validate:
            bucket.get_all_keys(headers, maxkeys=0)
        return bucket

    def create_bucket(self, bucket_name, headers=None,
                      location='', policy=None):
        """
        Creates a new located bucket. By default it's in the USA. You can pass
        Location.EU to create an European bucket.

        :type bucket_name: string
        :param bucket_name: The name of the new bucket

        :type headers: dict
        :param headers: Additional headers to pass along with
                        the request to AWS.

        :type location: :class:`boto.s3.connection.Location`
        :param location: The location of the new bucket

        :type policy: :class:`boto.s3.acl.CannedACLStrings`
        :param policy: A canned ACL policy that will be applied
                       to the new key in S3.

        """
        if not bucket_name.islower():
            raise BotoClientError("Bucket names must be lower case.")

        if policy:
            if headers:
                headers['x-amz-acl'] = policy
            else:
                headers = {'x-amz-acl' : policy}
        if location == '':
            data = ''
        else:
            data = '<CreateBucketConstraint><LocationConstraint>' + \
                    location + '</LocationConstraint></CreateBucketConstraint>'
        response = self.make_request('PUT', bucket_name, headers=headers,
                data=data)
        body = response.read()
        if response.status == 409:
            raise S3CreateError(response.status, response.reason, body)
        if response.status == 200:
            return Bucket(self, bucket_name)
        else:
            raise self.provider.storage_response_error(
                response.status, response.reason, body)

    def delete_bucket(self, bucket, headers=None):
        response = self.make_request('DELETE', bucket, headers=headers)
        body = response.read()
        if response.status != 204:
            raise self.provider.storage_response_error(
                response.status, response.reason, body)

<commit_msg>Making the special nc auth module compatible with updated boto signature code.<commit_after># Software License Agreement (BSD License)
#
# Copyright (c) 2009-2011, Eucalyptus Systems, Inc.
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms, with or
# without modification, are permitted provided that the following conditions
# are met:
#
#   Redistributions of source code must retain the above
#   copyright notice, this list of conditions and the
#   following disclaimer.
#
#   Redistributions in binary form must reproduce the above
#   copyright notice, this list of conditions and the
#   following disclaimer in the documentation and/or other
#   materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Author: Mitch Garnaat mgarnaat@eucalyptus.com

import urllib, base64
import time
from boto.connection import AWSAuthConnection
from boto import handler
from boto.resultset import ResultSet
from boto.exception import BotoClientError
from boto.exception import S3ResponseError
from boto.exception import S3CreateError
from boto.s3.bucket import Bucket

class EucaConnection(AWSAuthConnection):

    DefaultHost = 'localhost'
    DefaultPort = 8773

    def __init__(self, private_key_path, cert_path,
                 aws_access_key_id=None, aws_secret_access_key=None,
                 is_secure=False, port=DefaultPort, proxy=None, proxy_port=None,
                 proxy_user=None, proxy_pass=None,
                 host=DefaultHost, debug=0, https_connection_factory=None,
                 path='/'):
        self.private_key_path = private_key_path
        self.cert_path = cert_path
        AWSAuthConnection.__init__(self, host, aws_access_key_id,
                                   aws_secret_access_key,
                                   is_secure, port, proxy, proxy_port,
                                   proxy_user, proxy_pass,
                                   debug=debug,
                                   https_connection_factory=https_connection_factory,
                                   path=path)

    def _required_auth_capability(self):
        return ['euca-nc']

    def make_request(self, method='GET', bucket='', key='', headers=None,
                     data='', query_args=None, sender=None,
                     override_num_retries=None, action=None,
                     effective_user_id = None, params=None):
        if headers is None:
            headers = {}
        if params is None:
            params = {}
        if not effective_user_id:
            effective_user_id = self.aws_access_key_id
        if action:
            headers['EucaOperation'] = action
        headers['AWSAccessKeyId'] = effective_user_id
        cert_file = open(self.cert_path, 'r')
        cert_str = cert_file.read()
        cert_file.close()
        headers['EucaCert'] = base64.b64encode(cert_str)
        if not headers.has_key('Content-Length'):
            headers['Content-Length'] = str(len(data))
        if not headers.has_key('Date'):
            headers['Date'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
                                            time.gmtime())
        utf8_params = {}
        for key in params:
            utf8_params[key] = self.get_utf8_value(params[key])
        path_base = '/'
        path_base += "%s/" % bucket
        path = path_base + urllib.quote(key)
        http_request = self.build_base_http_request(method, path, None,
                                                    utf8_params,
                                                    headers, data,
                                                    self.server_name())
        return self._mexe(http_request, sender)

    def get_bucket(self, bucket_name, validate=True, headers=None):
        bucket = Bucket(self, bucket_name)
        if validate:
            bucket.get_all_keys(headers, maxkeys=0)
        return bucket

    def create_bucket(self, bucket_name, headers=None,
                      location='', policy=None):
        """
        Creates a new located bucket. By default it's in the USA. You can pass
        Location.EU to create an European bucket.

        :type bucket_name: string
        :param bucket_name: The name of the new bucket

        :type headers: dict
        :param headers: Additional headers to pass along with
                        the request to AWS.

        :type location: :class:`boto.s3.connection.Location`
        :param location: The location of the new bucket

        :type policy: :class:`boto.s3.acl.CannedACLStrings`
        :param policy: A canned ACL policy that will be applied
                       to the new key in S3.

        """
        if not bucket_name.islower():
            raise BotoClientError("Bucket names must be lower case.")

        if policy:
            if headers:
                headers['x-amz-acl'] = policy
            else:
                headers = {'x-amz-acl' : policy}
        if location == '':
            data = ''
        else:
            data = '<CreateBucketConstraint><LocationConstraint>' + \
                    location + '</LocationConstraint></CreateBucketConstraint>'
        response = self.make_request('PUT', bucket_name, headers=headers,
                data=data)
        body = response.read()
        if response.status == 409:
            raise S3CreateError(response.status, response.reason, body)
        if response.status == 200:
            return Bucket(self, bucket_name)
        else:
            raise self.provider.storage_response_error(
                response.status, response.reason, body)

    def delete_bucket(self, bucket, headers=None):
        response = self.make_request('DELETE', bucket, headers=headers)
        body = response.read()
        if response.status != 204:
            raise self.provider.storage_response_error(
                response.status, response.reason, body)

<|endoftext|>


<commit_before>#!/usr/bin/env python

import atexit
import os
import time
import threading

import flask
from flask.ext.pymongo import PyMongo
from slacker import Slacker

import credentials  # local deploy settings

SLACK_CLIENT_ID = '6154181110.20526331843'
AUTH_LINK = 'https://slack.com/oauth/authorize?team=T064J5B38&client_id=6154181110.20526331843&scope=identify,channels:history,channels:read,files:read,groups:history,groups:read,im:history,im:read,users:read'
LOGIN_LINK = 'https://slack.com/oauth/authorize?team=T064J5B38&client_id=6154181110.20526331843&scope=identify'

app = flask.Flask(__name__)
mongo = PyMongo(app)

timer_thread = threading.Thread()
timer_string = 'START
'

def redirect_msg(url, msg):
    return flask.render_template('redirect.htm',
                                 url_to=url,
                                 message=msg)

@app.route('/')
def index():
    if flask.request.args.get('code') is None and \
       flask.request.cookies.get('token') is None:
        return redirect_msg(LOGIN_LINK, 'Logging in')
    token = flask.request.cookies.get('token')
    if flask.request.cookies.get('token') is None:
        try:
            oauth = Slacker.oauth.access(
                client_id=SLACK_CLIENT_ID,
                client_secret=os.environ['SLACK_SECRET'],
                code=flask.request.args['code']).body
        except Exception as e:
            oauth = {}
        if oauth.get('ok') is None:
            return redirect_msg(LOGIN_LINK, 'Auth required')
        token = oauth['access_token']
    client = Slacker(token)
    user_info = client.auth.test().body
    response = flask.make_response(str(user_info))
    next_year = time.strftime("%a, %d-%b-%Y %T GMT",
                              time.gmtime(time.time()+365*24*60*60))
    response.set_cookie('token', token, expires=next_year)
    return response

@app.route('/timer')
def timer():
    def timer_two():
        global timer_string
        timer_string += 'timer_two
'

    def timer_one():
        global timer_string
        timer_string += 'timer_one
'
        timer_thread = threading.Timer(1, timer_two, ())
        timer_thread.start()
        time.sleep(2)
        timer_string += 'timer_one after sleep
'

    def stop_timer_thread():
        global yourThread
        timer_thread.cancel()

    global timer_thread
    if not timer_thread.is_alive():
        timer_thread = threading.Timer(1, timer_one, ())
        timer_thread.start()
        atexit.register(stop_timer_thread)
    return timer_string

def is_local_deploy():
    return 'LOCAL' == os.environ.get('PORT', 'LOCAL')

def is_production_deploy():
    return '1' == os.environ.get('PRODUCTION', '0')

def redirect_to_https():
    if 'http'==flask.request.headers.get('X-Forwarded-Proto', 'https'):
        url = flask.request.url.replace('http://', 'https://', 1)
        return flask.redirect(url, code=301)

if __name__ == "__main__":
    app.config['MONGO_URI'] = os.environ['MONGOLAB_URI']
    app.before_request(redirect_to_https)
    if is_local_deploy():
        app.run(port=8080, debug=True)
    else:
        app.run(host='0.0.0.0',
                port=int(os.environ['PORT']),
                debug=not is_production_deploy())
<commit_msg>Prepare import for Slack archive<commit_after>#!/usr/bin/env python

import atexit
import json
import os
import time
import threading
from zipfile import ZipFile

import flask
from flask.ext.pymongo import PyMongo
from slacker import Slacker

import credentials  # local deploy settings

SLACK_CLIENT_ID = '6154181110.20526331843'
AUTH_LINK = 'https://slack.com/oauth/authorize?team=T064J5B38&client_id=6154181110.20526331843&scope=identify,channels:history,channels:read,files:read,groups:history,groups:read,im:history,im:read,users:read'
LOGIN_LINK = 'https://slack.com/oauth/authorize?team=T064J5B38&client_id=6154181110.20526331843&scope=identify'

app = flask.Flask(__name__)
mongo = PyMongo(app)

timer_thread = threading.Thread()
timer_string = 'START
'

def redirect_msg(url, msg):
    return flask.render_template('redirect.htm',
                                 url_to=url,
                                 message=msg)

@app.route('/')
def index():
    m = mongo
    b = 7/(3-3)
    if flask.request.args.get('code') is None and \
       flask.request.cookies.get('token') is None:
        return redirect_msg(LOGIN_LINK, 'Logging in')
    token = flask.request.cookies.get('token')
    if flask.request.cookies.get('token') is None:
        try:
            oauth = Slacker.oauth.access(
                client_id=SLACK_CLIENT_ID,
                client_secret=os.environ['SLACK_SECRET'],
                code=flask.request.args['code']).body
        except Exception as e:
            oauth = {}
        if oauth.get('ok') is None:
            return redirect_msg(LOGIN_LINK, 'Auth required')
        token = oauth['access_token']
    client = Slacker(token)
    user_info = client.auth.test().body
    response = flask.make_response(str(user_info))
    next_year = time.strftime("%a, %d-%b-%Y %T GMT",
                              time.gmtime(time.time()+365*24*60*60))
    response.set_cookie('token', token, expires=next_year)
    return response

@app.route('/upload')
def upload():
    def import_zip_thread():
        global timer_string
        with ZipFile('archive.zip') as archive:
            with archive.open('channels.json') as channels:
                chans = json.loads(channels.read())
                for chan in chans:
                    mongo.db['channels']
                    timer_string += chan['purpose']['value'] + '
'
                    time.sleep(1)

    def stop_timer_thread():
        global yourThread
        timer_thread.cancel()

    global timer_thread
    if not timer_thread.is_alive():
        timer_thread = threading.Timer(0, import_zip_thread, ())
        timer_thread.start()
        atexit.register(stop_timer_thread)
    return timer_string

def is_local_deploy():
    return 'LOCAL' == os.environ.get('PORT', 'LOCAL')

def is_production_deploy():
    return '1' == os.environ.get('PRODUCTION', '0')

def redirect_to_https():
    if 'http'==flask.request.headers.get('X-Forwarded-Proto', 'https'):
        url = flask.request.url.replace('http://', 'https://', 1)
        return flask.redirect(url, code=301)

if __name__ == "__main__":
    app.config['MONGO_URI'] = os.environ['MONGOLAB_URI']
    app.before_request(redirect_to_https)
    if is_local_deploy():
        app.run(port=8080, debug=True)
    else:
        app.run(host='0.0.0.0',
                port=int(os.environ['PORT']),
                debug=not is_production_deploy())
<|endoftext|>


<commit_before># -------------------
# Imports
# -------------------

from flask import Flask, make_response, request, current_app, jsonify
from datetime import datetime, timedelta
from functools import update_wrapper
import json, os, requests, time
from flask.ext.heroku import Heroku
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy.ext.mutable import Mutable
from sqlalchemy import types
import flask.ext.restless
from dictalchemy import make_class_dictable

# -------------------
# Init
# -------------------

app = Flask(__name__)
heroku = Heroku(app)
db = SQLAlchemy(app)
make_class_dictable(db.Model)

# -------------------
# Settings
# -------------------

def add_cors_header(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type'
    response.headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, PATCH, DELETE, OPTIONS'
    return response
app.after_request(add_cors_header)

# -------------------
# Types
# -------------------

class JsonType(Mutable, types.TypeDecorator):
    ''' JSON wrapper type for TEXT database storage.

        References:
        http://stackoverflow.com/questions/4038314/sqlalchemy-json-as-blob-text
        http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/mutable.html
    '''
    impl = types.Unicode

    def process_bind_param(self, value, engine):
        return unicode(json.dumps(value))

    def process_result_value(self, value, engine):
        if value:
            return json.loads(value)
        else:
            # default can also be a list
            return {}

# -------------------
# Models
# -------------------

class Organization(db.Model):
    '''
        Brigades and other civic tech organizations
    '''
    #Columns
    name = db.Column(db.Unicode(), primary_key=True)
    website = db.Column(db.Unicode())
    events_url = db.Column(db.Unicode())
    rss = db.Column(db.Unicode())
    projects_list_url = db.Column(db.Unicode())
    type = db.Column(db.Unicode())
    city = db.Column(db.Unicode())
    latitude = db.Column(db.Float())
    longitude = db.Column(db.Float())
    keep = db.Column(db.Boolean())

    # Relationships
    events = db.relationship('Event')
    recent_stories = db.relationship('Story') # Stories already limited to two most recent
    projects = db.relationship('Project')

    def __init__(self, name, website=None, events_url=None,
                 rss=None, projects_list_url=None, type=None, city=None, latitude=None, longitude=None):
        self.name = name
        self.website = website
        self.events_url = events_url
        self.rss = rss
        self.projects_list_url = projects_list_url
        self.type = type
        self.city = city
        self.latitude = latitude
        self.longitude = longitude
        self.keep = True

    def recent_events(self):
        '''
            Return the two most recent events
        '''
        recent_events = Event.query.order_by(Event.start_time.desc()).limit(2).all()
        recent_events_json = [row.asdict() for row in recent_events]
        return recent_events_json

    def recent_projects(self):
        '''
            Return the three most recent projects
        '''
        all_projects = Project.query.filter_by(organization_name=self.name).all()
        all_projects_json = [project.asdict() for project in all_projects]
        all_projects_json.sort(key=lambda k: k['github_details']['updated_at'], reverse=True)
        recent_projects = all_projects_json[0:3]
        return recent_projects

    def all_events(self):
        '''
            API link to all an orgs events
        '''
        return 'http://civic-tech-movement.codeforamerica.org/api/'+self.name+'/events'

    def all_projects(self):
        '''
            API link to all an orgs projects
        '''
        return 'http://civic-tech-movement.codeforamerica.org/api/'+self.name+'/projects'

    def all_stories(self):
        '''
            API link to all an orgs stories
        '''
        return 'http://civic-tech-movement.codeforamerica.org/api/'+self.name+'/stories'

class Story(db.Model):
    '''
        Blog posts from a Brigade.
    '''
    # Columns
    id = db.Column(db.Integer(), primary_key=True)
    title = db.Column(db.Unicode())
    link = db.Column(db.Unicode())
    type = db.Column(db.Unicode())

    # Relationships
    organization = db.relationship('Organization')
    organization_name = db.Column(db.Unicode(), db.ForeignKey('organization.name'))

    def __init__(self, title=None, link=None, type=None, organization_name=None):
        self.title = title
        self.link = link
        self.type = type
        self.organization_name = organization_name

class Project(db.Model):
    '''
        Civic tech projects on GitHub
    '''
    # Columns
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.Unicode())
    code_url = db.Column(db.Unicode())
    link_url = db.Column(db.Unicode())
    description = db.Column(db.Unicode())
    type = db.Column(db.Unicode())
    categories = db.Column(db.Unicode())
    github_details = db.Column(JsonType())
    keep = db.Column(db.Boolean())

    # Relationships
    organization = db.relationship('Organization')
    organization_name = db.Column(db.Unicode(), db.ForeignKey('organization.name'))

    def __init__(self, name, code_url=None, link_url=None,
                 description=None, type=None, categories=None,
                 github_details=None, organization_name=None, keep=None):
        self.name = name
        self.code_url = code_url
        self.link_url = link_url
        self.description = description
        self.type = type
        self.categories = categories
        self.github_details = github_details
        self.organization_name = organization_name
        self.keep = True

class Event(db.Model):
    '''
        Organizations events from Meetup
    '''
    # Columns
    id  = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.Unicode())
    description = db.Column(db.Unicode())
    event_url = db.Column(db.Unicode())
    location = db.Column(db.Unicode())
    created_at = db.Column(db.Unicode())
    start_time = db.Column(db.DateTime())
    end_time = db.Column(db.DateTime())
    keep = db.Column(db.Boolean())

    # Relationships
    organization = db.relationship('Organization')
    organization_name = db.Column(db.Unicode(), db.ForeignKey('organization.name'))

    def __init__(self, name, event_url, start_time, created_at,
                 organization_name, location=None, end_time=None, description=None):
        self.name = name
        self.description = description
        self.location = location
        self.event_url = event_url
        self.start_time = start_time
        self.end_time = end_time
        self.organization_name = organization_name
        self.created_at = created_at
        self.keep = True

# -------------------
# API
# -------------------
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
kwargs = dict(exclude_columns=['keep'], max_results_per_page=None)
org_kwargs = kwargs.copy()
org_kwargs['include_methods'] = ['recent_events','recent_projects','all_stories','all_events','all_projects']
org_kwargs['exclude_columns'] = ['keep','events','projects']
manager.create_api(Organization, collection_name='organizations', **org_kwargs)
manager.create_api(Story, collection_name='stories', **kwargs)
manager.create_api(Project, collection_name='projects', **kwargs)
manager.create_api(Event, collection_name='events', **kwargs)

@app.route('/api/organizations.geojson')
def get_organizations_geojson():
    ''' GeoJSON response option for organizations.
    '''
    geojson = dict(type='GeometryCollection', features=[])

    for org in db.session.query(Organization):
        # The unique identifier of an organization is its name.
        id = org.name

        # Pick out all the field names without an underscore as the first char.
        keys = [k for k in org.__dict__.keys() if not k.startswith('_')]

        # Pick out all the properties that aren't part of the location.
        names = [k for k in keys if k not in ('latitude', 'longitude', 'keep')]
        props = dict([(k, getattr(org, k)) for k in names])

        # GeoJSON Point geometry, http://geojson.org/geojson-spec.html#point
        geom = dict(type='Point', coordinates=[org.longitude, org.latitude])

        feature = dict(type='Feature', id=id, properties=props, geometry=geom)
        geojson['features'].append(feature)

    response = make_response(json.dumps(geojson, indent=2))
    response.headers['Content-Type'] = 'application/json'

    return response

@app.route("/api/organizations/<organization_name>/events")
def get_orgs_events(organization_name):
    '''
        A cleaner url for getting an organizations events
        Better than /api/events?q={"filters":[{"name":"organization_name","op":"eq","val":"Code for San Francisco"}]}
    '''
    orgs_events = Event.query.filter_by(organization_name=organization_name).all()
    orgs_events = [event.asdict() for event in orgs_events]
    response = {
        "num_results" : len(orgs_events),
        "objects" : orgs_events,
        "page" : 1,
        "total_pages" : 1
    }
    return jsonify(response)

@app.route("/api/organizations/<organization_name>/stories")
def get_orgs_stories(organization_name):
    '''
        A cleaner url for getting an organizations stories
    '''
    orgs_stories = Story.query.filter_by(organization_name=organization_name).all()
    orgs_stories = [story.asdict() for story in orgs_stories]
    response = {
        "num_results" : len(orgs_stories),
        "objects" : orgs_stories,
        "page" : 1,
        "total_pages" : 1
    }
    return jsonify(response)

@app.route("/api/organizations/<organization_name>/projects")
def get_orgs_projects(organization_name):
    '''
        A cleaner url for getting an organizations projects
    '''
    orgs_projects = Project.query.filter_by(organization_name=organization_name).all()
    orgs_projects = [project.asdict() for project in orgs_projects]
    response = {
        "num_results" : len(orgs_projects),
        "objects" : orgs_projects,
        "page" : 1,
        "total_pages" : 1
    }
    return jsonify(response)

# -------------------
# Routes
# -------------------

@app.route('/.well-known/status')
def well_known_status():
    ''' Return status information for Engine Light.

        http://engine-light.codeforamerica.org
    '''
    try:
        org = db.session.query(Organization).limit(1).first()
        project = db.session.query(Project).limit(1).first()

        if not hasattr(project, 'name'):
            status = 'Sample project is missing a name'

        elif not hasattr(org, 'name'):
            status = 'Sample project is missing a name'

        else:
            status = 'ok'

    except Exception, e:
        status = 'Error: ' + str(e)

    state = dict(status=status, updated=int(time.time()), resources=[])
    state.update(dict(dependencies=['Meetup', 'Github', 'PostgreSQL']))

    response = make_response(json.dumps(state, indent=2))
    response.headers['Content-Type'] = 'application/json'

    return response

@app.route("/")
def index():
    return '''

    <title>Civic Tech Movement API</title>

Read more about me at codeforamerica/civic-json-worker.

Some data:

Projects

'''

if __name__ == "__main__":
    app.run(debug=True)
<commit_msg>Fixed full links for all_stories etc.<commit_after># -------------------
# Imports
# -------------------

from flask import Flask, make_response, request, current_app, jsonify
from datetime import datetime, timedelta
from functools import update_wrapper
import json, os, requests, time
from flask.ext.heroku import Heroku
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy.ext.mutable import Mutable
from sqlalchemy import types
import flask.ext.restless
from dictalchemy import make_class_dictable

# -------------------
# Init
# -------------------

app = Flask(__name__)
heroku = Heroku(app)
db = SQLAlchemy(app)
make_class_dictable(db.Model)

# -------------------
# Settings
# -------------------

def add_cors_header(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type'
    response.headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, PATCH, DELETE, OPTIONS'
    return response
app.after_request(add_cors_header)

# -------------------
# Types
# -------------------

class JsonType(Mutable, types.TypeDecorator):
    ''' JSON wrapper type for TEXT database storage.

        References:
        http://stackoverflow.com/questions/4038314/sqlalchemy-json-as-blob-text
        http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/mutable.html
    '''
    impl = types.Unicode

    def process_bind_param(self, value, engine):
        return unicode(json.dumps(value))

    def process_result_value(self, value, engine):
        if value:
            return json.loads(value)
        else:
            # default can also be a list
            return {}

# -------------------
# Models
# -------------------

class Organization(db.Model):
    '''
        Brigades and other civic tech organizations
    '''
    #Columns
    name = db.Column(db.Unicode(), primary_key=True)
    website = db.Column(db.Unicode())
    events_url = db.Column(db.Unicode())
    rss = db.Column(db.Unicode())
    projects_list_url = db.Column(db.Unicode())
    type = db.Column(db.Unicode())
    city = db.Column(db.Unicode())
    latitude = db.Column(db.Float())
    longitude = db.Column(db.Float())
    keep = db.Column(db.Boolean())

    # Relationships
    events = db.relationship('Event')
    recent_stories = db.relationship('Story') # Stories already limited to two most recent
    projects = db.relationship('Project')

    def __init__(self, name, website=None, events_url=None,
                 rss=None, projects_list_url=None, type=None, city=None, latitude=None, longitude=None):
        self.name = name
        self.website = website
        self.events_url = events_url
        self.rss = rss
        self.projects_list_url = projects_list_url
        self.type = type
        self.city = city
        self.latitude = latitude
        self.longitude = longitude
        self.keep = True

    def recent_events(self):
        '''
            Return the two most recent events
        '''
        recent_events = Event.query.order_by(Event.start_time.desc()).limit(2).all()
        recent_events_json = [row.asdict() for row in recent_events]
        return recent_events_json

    def recent_projects(self):
        '''
            Return the three most recent projects
        '''
        all_projects = Project.query.filter_by(organization_name=self.name).all()
        all_projects_json = [project.asdict() for project in all_projects]
        all_projects_json.sort(key=lambda k: k['github_details']['updated_at'], reverse=True)
        recent_projects = all_projects_json[0:3]
        return recent_projects

    def all_events(self):
        '''
            API link to all an orgs events
        '''
        return 'http://civic-tech-movement.codeforamerica.org/api/organizations/'+self.name+'/events'

    def all_projects(self):
        '''
            API link to all an orgs projects
        '''
        return 'http://civic-tech-movement.codeforamerica.org/api/organizations/'+self.name+'/projects'

    def all_stories(self):
        '''
            API link to all an orgs stories
        '''
        return 'http://civic-tech-movement.codeforamerica.org/api/organizations/'+self.name+'/stories'

class Story(db.Model):
    '''
        Blog posts from a Brigade.
    '''
    # Columns
    id = db.Column(db.Integer(), primary_key=True)
    title = db.Column(db.Unicode())
    link = db.Column(db.Unicode())
    type = db.Column(db.Unicode())

    # Relationships
    organization = db.relationship('Organization')
    organization_name = db.Column(db.Unicode(), db.ForeignKey('organization.name'))

    def __init__(self, title=None, link=None, type=None, organization_name=None):
        self.title = title
        self.link = link
        self.type = type
        self.organization_name = organization_name

class Project(db.Model):
    '''
        Civic tech projects on GitHub
    '''
    # Columns
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.Unicode())
    code_url = db.Column(db.Unicode())
    link_url = db.Column(db.Unicode())
    description = db.Column(db.Unicode())
    type = db.Column(db.Unicode())
    categories = db.Column(db.Unicode())
    github_details = db.Column(JsonType())
    keep = db.Column(db.Boolean())

    # Relationships
    organization = db.relationship('Organization')
    organization_name = db.Column(db.Unicode(), db.ForeignKey('organization.name'))

    def __init__(self, name, code_url=None, link_url=None,
                 description=None, type=None, categories=None,
                 github_details=None, organization_name=None, keep=None):
        self.name = name
        self.code_url = code_url
        self.link_url = link_url
        self.description = description
        self.type = type
        self.categories = categories
        self.github_details = github_details
        self.organization_name = organization_name
        self.keep = True

class Event(db.Model):
    '''
        Organizations events from Meetup
    '''
    # Columns
    id  = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.Unicode())
    description = db.Column(db.Unicode())
    event_url = db.Column(db.Unicode())
    location = db.Column(db.Unicode())
    created_at = db.Column(db.Unicode())
    start_time = db.Column(db.DateTime())
    end_time = db.Column(db.DateTime())
    keep = db.Column(db.Boolean())

    # Relationships
    organization = db.relationship('Organization')
    organization_name = db.Column(db.Unicode(), db.ForeignKey('organization.name'))

    def __init__(self, name, event_url, start_time, created_at,
                 organization_name, location=None, end_time=None, description=None):
        self.name = name
        self.description = description
        self.location = location
        self.event_url = event_url
        self.start_time = start_time
        self.end_time = end_time
        self.organization_name = organization_name
        self.created_at = created_at
        self.keep = True

# -------------------
# API
# -------------------
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
kwargs = dict(exclude_columns=['keep'], max_results_per_page=None)
org_kwargs = kwargs.copy()
org_kwargs['include_methods'] = ['recent_events','recent_projects','all_stories','all_events','all_projects']
org_kwargs['exclude_columns'] = ['keep','events','projects']
manager.create_api(Organization, collection_name='organizations', **org_kwargs)
manager.create_api(Story, collection_name='stories', **kwargs)
manager.create_api(Project, collection_name='projects', **kwargs)
manager.create_api(Event, collection_name='events', **kwargs)

@app.route('/api/organizations.geojson')
def get_organizations_geojson():
    ''' GeoJSON response option for organizations.
    '''
    geojson = dict(type='GeometryCollection', features=[])

    for org in db.session.query(Organization):
        # The unique identifier of an organization is its name.
        id = org.name

        # Pick out all the field names without an underscore as the first char.
        keys = [k for k in org.__dict__.keys() if not k.startswith('_')]

        # Pick out all the properties that aren't part of the location.
        names = [k for k in keys if k not in ('latitude', 'longitude', 'keep')]
        props = dict([(k, getattr(org, k)) for k in names])

        # GeoJSON Point geometry, http://geojson.org/geojson-spec.html#point
        geom = dict(type='Point', coordinates=[org.longitude, org.latitude])

        feature = dict(type='Feature', id=id, properties=props, geometry=geom)
        geojson['features'].append(feature)

    response = make_response(json.dumps(geojson, indent=2))
    response.headers['Content-Type'] = 'application/json'

    return response

@app.route("/api/organizations/<organization_name>/events")
def get_orgs_events(organization_name):
    '''
        A cleaner url for getting an organizations events
        Better than /api/events?q={"filters":[{"name":"organization_name","op":"eq","val":"Code for San Francisco"}]}
    '''
    orgs_events = Event.query.filter_by(organization_name=organization_name).all()
    orgs_events = [event.asdict() for event in orgs_events]
    response = {
        "num_results" : len(orgs_events),
        "objects" : orgs_events,
        "page" : 1,
        "total_pages" : 1
    }
    return jsonify(response)

@app.route("/api/organizations/<organization_name>/stories")
def get_orgs_stories(organization_name):
    '''
        A cleaner url for getting an organizations stories
    '''
    orgs_stories = Story.query.filter_by(organization_name=organization_name).all()
    orgs_stories = [story.asdict() for story in orgs_stories]
    response = {
        "num_results" : len(orgs_stories),
        "objects" : orgs_stories,
        "page" : 1,
        "total_pages" : 1
    }
    return jsonify(response)

@app.route("/api/organizations/<organization_name>/projects")
def get_orgs_projects(organization_name):
    '''
        A cleaner url for getting an organizations projects
    '''
    orgs_projects = Project.query.filter_by(organization_name=organization_name).all()
    orgs_projects = [project.asdict() for project in orgs_projects]
    response = {
        "num_results" : len(orgs_projects),
        "objects" : orgs_projects,
        "page" : 1,
        "total_pages" : 1
    }
    return jsonify(response)

# -------------------
# Routes
# -------------------

@app.route('/.well-known/status')
def well_known_status():
    ''' Return status information for Engine Light.

        http://engine-light.codeforamerica.org
    '''
    try:
        org = db.session.query(Organization).limit(1).first()
        project = db.session.query(Project).limit(1).first()

        if not hasattr(project, 'name'):
            status = 'Sample project is missing a name'

        elif not hasattr(org, 'name'):
            status = 'Sample project is missing a name'

        else:
            status = 'ok'

    except Exception, e:
        status = 'Error: ' + str(e)

    state = dict(status=status, updated=int(time.time()), resources=[])
    state.update(dict(dependencies=['Meetup', 'Github', 'PostgreSQL']))

    response = make_response(json.dumps(state, indent=2))
    response.headers['Content-Type'] = 'application/json'

    return response

@app.route("/")
def index():
    return '''

    <title>Civic Tech Movement API</title>

Read more about me at codeforamerica/civic-json-worker.

Some data:

Projects

'''

if __name__ == "__main__":
    app.run(debug=True)
<|endoftext|>