<commit_before>#!/usr/bin/env python
"""
Application main for the mixmind app
"""
import os
import random
import logging

from flask import Flask, render_template, flash, request, send_file, jsonify, redirect, after_request
from flask_uploads import UploadSet, DATA, configure_uploads
from werkzeug.utils import secure_filename # ??
import urllib
import flask_login
from flask_security import Security, SQLAlchemySessionUserDatastore, login_required, roles_required

import recipe as drink_recipe
import util
import formatted_menu
from barstock import Barstock_SQL as Barstock
from notifier import Notifier
from forms import DrinksForm, OrderForm, RecipeForm, RecipeListSelector, BarstockForm, LoginForm, RegisterUserForm
from database import db_session, init_db, db_file
from models import User, Role


"""
NOTES:
^ Need to reaplace pandas version of barstock - time for sql!
* refactor messages to look nicer
* menu schemas
    - would be able to include definitive item lists for serving, ice, tag, etc.
* update bootstrap
* user permissons (non-logged in vs admin)
    - flask-praetorian
    - google app engine
    - backend DB?
    - domain name
        - LetsEncrypt certs
* hardening
    - moar logging
    - test error handling
    - support concurrent users, single admin
* configuration management
    - defaults plus management
    - support for modifying the "bartender on duty" aka Notifier's secret info
    - disable the order button unless we are "open"
"""
log = logging.getLogger(__name__)

# app config TODO move to __init__
app = Flask(__name__)
app.config.from_object(__name__)
with open('local_secret') as fp: # TODO config management
    app.config['SECRET_KEY'] = fp.read().strip()
app.config['UPLOADS_DEFAULT_DEST'] = './stockdb'
datafiles = UploadSet('datafiles', DATA)
configure_uploads(app, (datafiles,))
app.config['SECURITY_PASSWORD_SALT'] = '<PASSWORD>'

# Setup Flask-Security
user_datastore = SQLAlchemySessionUserDatastore(db_session, User, Role)
security = Security(app, user_datastore)

# Create a user to test with
@app.before_first_request
def initialize_user_datastore():
    if not os.path.isdir('db/'):
        os.mkdir('db/')
    if not os.path.isfile(db_file):
        init_db()
        user_datastore.create_user(email='<EMAIL>', password='password')
        user_datastore.create_role(name='admin', description='An admin user may modify the parameters of the app backend')
        user_datastore.create_role(name='customer', description='Customer may register to make it easier to order drinks')
        db_session.commit()
        admin = user_datastore.find_role('admin')
        user = user_datastore.find_user(email='<EMAIL>')
        user_datastore.add_role_to_user(user, admin)
        db_session.commit()

# required for SQLAlchemy scoped_session registry
@app.after_request
def clean_up_db_sessions():
    log.debug("Remove SQLAlchemy session for request: {}".format(id(request)))
    db_session.remove()

# Views
@app.route('/test')
@login_required
@roles_required('admin')
def home_test():
    return jsonify({'test': 'Here you go!'})

class MixMindServer():
    def __init__(self, recipes=['recipes_schubar.json','IBA_all.json'], barstock_files=['Barstock - Sheet1.csv']):
        self.recipe_files = recipes
        self.barstock_files = barstock_files # TODO get from datastore and cloud storage
        self.base_recipes = util.load_recipe_json(recipes)
        self.barstock = Barstock.load(barstock_files)
        self.recipes = [drink_recipe.DrinkRecipe(name, recipe).generate_examples(self.barstock, stats=True) for name, recipe in self.base_recipes.iteritems()]
        self.notifier = Notifier('secrets.json', 'simpler_email_template.html')
        self.default_margin = 1.10

        url = "https://ipv4.icanhazip.com/"
        try:
            self.ip = urllib.urlopen(url).read().rstrip('\n')
            print "Server running on: {}".format(self.ip)
        except Exception as err:
            print err

    def get_ingredients_table(self):
        raise NotImplementedError("unavailable for now")
        df = self.barstock.sorted_df()
        df.Proof = df.Proof.astype('int')
        df['Size (mL)'] = df['Size (mL)'].astype('int')<commit_msg>Use new sql barstock; init db but still not working...<commit_after>#!/usr/bin/env python
"""
Application main for the mixmind app
"""
import os
import random
import logging

from flask import Flask, render_template, flash, request, send_file, jsonify, redirect
from flask_uploads import UploadSet, DATA, configure_uploads
from werkzeug.utils import secure_filename # ??
import urllib
import flask_login
from flask_security import Security, SQLAlchemySessionUserDatastore, login_required, roles_required

import recipe as drink_recipe
import util
import formatted_menu
from barstock import get_barstock_instance
from notifier import Notifier
from forms import DrinksForm, OrderForm, RecipeForm, RecipeListSelector, BarstockForm, LoginForm, RegisterUserForm
from database import db_session, init_db
from models import User, Role


"""
NOTES:
^ Need to reaplace pandas version of barstock - time for sql!
* refactor messages to look nicer
* menu schemas
    - would be able to include definitive item lists for serving, ice, tag, etc.
* update bootstrap
* user permissons (non-logged in vs admin)
    - flask-praetorian
    - google app engine
    - backend DB?
    - domain name
        - LetsEncrypt certs
* hardening
    - moar logging
    - test error handling
    - support concurrent users, single admin
* configuration management
    - defaults plus management
    - support for modifying the "bartender on duty" aka Notifier's secret info
    - disable the order button unless we are "open"
"""
log = logging.getLogger(__name__)

# app config TODO move to __init__
app = Flask(__name__)
app.config.from_object(__name__)
with open('local_secret') as fp: # TODO config management
    app.config['SECRET_KEY'] = fp.read().strip()
app.config['UPLOADS_DEFAULT_DEST'] = './stockdb'
datafiles = UploadSet('datafiles', DATA)
configure_uploads(app, (datafiles,))
app.config['SECURITY_PASSWORD_SALT'] = '<PASSWORD>'
init_db()

# Setup Flask-Security
user_datastore = SQLAlchemySessionUserDatastore(db_session, User, Role)
security = Security(app, user_datastore)

# Create a user to test with
@app.before_first_request
def initialize_user_datastore():
    init_db()
    if not os.path.isdir('db/'):
        os.mkdir('db/')
        user_datastore.create_user(email='<EMAIL>', password='password')
        user_datastore.create_role(name='admin', description='An admin user may modify the parameters of the app backend')
        user_datastore.create_role(name='customer', description='Customer may register to make it easier to order drinks')
        db_session.commit()
        admin = user_datastore.find_role('admin')
        user = user_datastore.find_user(email='<EMAIL>')
        user_datastore.add_role_to_user(user, admin)
        db_session.commit()

# required for SQLAlchemy scoped_session registry
@app.after_request
def clean_up_db_sessions():
    log.debug("Remove SQLAlchemy session for request: {}".format(id(request)))
    db_session.remove()

# Views
@app.route('/test')
@login_required
@roles_required('admin')
def home_test():
    return jsonify({'test': 'Here you go!'})

class MixMindServer():
    def __init__(self, recipes=['recipes_schubar.json','IBA_all.json'], barstock_files=['Barstock - Sheet1.csv']):
        self.recipe_files = recipes
        self.barstock_files = barstock_files # TODO get from datastore and cloud storage
        self.base_recipes = util.load_recipe_json(recipes)
        self.barstock = get_barstock_instance(barstock_files, use_sql=True)
        self.recipes = [drink_recipe.DrinkRecipe(name, recipe).generate_examples(self.barstock, stats=True) for name, recipe in self.base_recipes.iteritems()]
        self.notifier = Notifier('secrets.json', 'simpler_email_template.html')
        self.default_margin = 1.10

        url = "https://ipv4.icanhazip.com/"
        try:
            self.ip = urllib.urlopen(url).read().rstrip('\n')
            print "Server running on: {}".format(self.ip)
        except Exception as err:
            print err

    def get_ingredients_table(self):
        raise NotImplementedError("unavailable for now")
        df = self.barstock.sorted_df()
        df.Proof = df.Proof.astype('int')
        df['Size (mL)'] = df['Size (mL)'].astype('int')
{'fraction_non_alphanumeric': 0.10258232646292348, 'fraction_numerical': 0.0011845534233593934, 'mean_word_length': 4.157605375687233, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2094170', 'n_tokens_mistral': 2610, 'n_tokens_neox': 2541, 'n_words': 701}