예제 #1
0
def send_mail(email, type, data):
    if is_dev(): return
    if type == 'forgot-password':
        subject = "Gnothi reset password"
        body = f"Click this link to reset your password: {url}/reset-password?token={data}"
    elif type == 'welcome':
        subject = "Welcome to Gnothi"
        body = f"Thank you for registering a Gnothi account! Start journaling away."
    elif type == 'action':
        subject = f"Gnothi: {data['category']}/{data['action']}"
        body = subject
    else:
        return

    ses = boto3.client('ses')
    ses.send_email(Source=vars.EMAIL_SES_EMAIL_SOURCE,
                   Destination={'ToAddresses': [email]},
                   Message={
                       'Subject': {
                           'Data': subject
                       },
                       'Body': {
                           'Text': {
                               'Data': body
                           }
                       }
                   })
예제 #2
0
def cloud_down_maybe(sess):
    if is_dev(): return

    # 15 minutes since last job
    active = M.Job.last_job(sess) < 15
    if active or vars.MACHINE in ['desktop', 'laptop']:
        return

    sess.query(M.Machine).get(vars.MACHINE).delete()
    sess.commit()
    exit(0)
예제 #3
0
def cloud_down_maybe(sess):
    if is_dev(): return

    # 15 minutes since last user checkin
    active = M.User.last_checkin(sess) < 15
    if active or vars.MACHINE in ['desktop', 'laptop']:
        return

    sess.query(M.Machine).filter_by(id=vars.MACHINE).delete()
    sess.commit()
    exit(0)
예제 #4
0
def cloud_up_maybe():
    if is_dev(): return
    with session() as sess:
        if M.User.last_checkin(sess) > 15: return
        if M.Machine.gpu_status(sess) in ("on", "pending"): return

        logger.warning("Initing AWS Batch")
        M.Machine.notify_online(sess, 'batch', 'pending')
        boto3.client('batch').submit_job(
            jobName=str(uuid4()),
            jobQueue='gnothi-jq',
            jobDefinition='gnothi-jd',
        )
예제 #5
0
def cloud_up_maybe():
    if is_dev(): return
    with session() as sess:
        if M.User.last_checkin(sess) > 10: return
        if M.Machine.gpu_status(sess) != "off": return

        logger.warning("Initing Paperspace")
        M.Machine.notify_online(sess, 'paperspace', 'pending')
        jobs = job_client.list()
        if any([j.state in up_states for j in jobs]):
            return

        vars_ = {**dict(vars), **{'MACHINE': 'paperspace'}}
        return job_client.create(machine_type='K80',
                                 container='lefnire/gnothi:gpu-0.0.13',
                                 project_id=vars.PAPERSPACE_PROJECT_ID,
                                 is_preemptible=True,
                                 command='python app/run.py',
                                 env_vars=vars_)
예제 #6
0
def send_mail(email, type, data):
    if is_dev(): return
    if type == 'forgot-password':
        body = f"Click this link to confirm your account: {url}/reset-password?token={data}"
    elif type == 'welcome':
        body = f"Thank you for registering a Gnothi account! Start journaling away."
    else: return

    ses = boto3.client('ses')
    ses.send_email(
        Source=vars.EMAIL_SES_EMAIL_SOURCE,
        Destination={'ToAddresses': [email]},
        Message={
            'Subject': {'Data': 'Confirm Your Account'},
            'Body': {
                'Text': {'Data': body}
            }
        }
    )
예제 #7
0
from app.app_app import app as app_
import app.app_jwt
import app.app_routes
from common.utils import is_dev

app = app_

if __name__ == "__main__":
    args_ = {'debug': True} if is_dev() else {'port': 80}
    app.run(host='0.0.0.0', **args_)
예제 #8
0
def sync_for(user):
    if is_dev(): return
    if not (user.habitica_user_id and user.habitica_api_token):
        return
    # https://habitica.com/apidoc/#api-Task-GetUserTasks
    logger.info("Calling Habitica")
    headers = {
        "Content-Type": "application/json",
        "x-api-user": user.habitica_user_id,
        "x-api-key": user.habitica_api_token,
        "x-client": f"{vars.HABIT_USER}-{vars.HABIT_APP}"
    }
    tasks = requests.get('https://habitica.com/api/v3/tasks/user',
                         headers=headers).json()['data']
    huser = requests.get(
        'https://habitica.com/api/v3/user?userFields=lastCron,needsCron,preferences',
        headers=headers).json()['data']

    # don't pull field if they're in the inn
    if huser['preferences']['sleep']: return

    # Use SQL to determine day, so not managing timezones in python + sql
    tz = M.User.tz(db.session, user.id)
    last_cron = db.session.execute(
        text("""
    select date(:lastCron ::timestamptz at time zone :tz)::text last_cron
    """), dict(lastCron=huser['lastCron'], tz=tz)).fetchone().last_cron

    f_map = {f.service_id: f for f in user.fields}
    t_map = {task['id']: task for task in tasks}

    # Remove Habitica-deleted tasks
    for f in user.fields:
        if f.service != 'habitica': continue
        if f.service_id not in t_map:
            db.session.delete(f)
    db.session.commit()

    # Add/update tasks from Habitica
    for task in tasks:
        # {id, text, type, value}
        # habit: {counterUp, counterDown}
        # daily:{checklist: [{completed}], completed, isDue}

        # only care about habits/dailies
        if task['type'] not in ['habit', 'daily']: continue

        f = f_map.get(task['id'], None)
        if not f:
            # Field doesn't exist here yet, add it.
            # TODO delete things here if deleted in habitica
            f = M.Field(service='habitica',
                        service_id=task['id'],
                        name=task['text'],
                        type='number')
            user.fields.append(f)
        # Text has changed on Habitica, update here
        if f.name != task['text']:
            f.name = task['text']

        db.session.commit()  # for f to have f.id

        value = 0.
        # Habit
        if task['type'] == 'habit':
            value = (task['counterUp'] or 0.) - (task['counterDown'] or 0.)
        # Daily
        else:
            value = 1. if task['completed'] \
                else 0. if not task['isDue'] \
                else -1.

            # With Checklist
            cl = task['checklist']
            if (not task['completed']) and any(c['completed'] for c in cl):
                value = sum(c['completed'] for c in cl) / len(cl)

        M.FieldEntry.upsert(db.session,
                            user_id=user.id,
                            field_id=f.id,
                            value=value,
                            day=last_cron)
        M.Field.update_avg(f.id)
        logger.info(task['text'] + " done")
예제 #9
0
	def render(self, template_path, extra_context={}, output='html'):
		"""render(template_path, extra_context={}, output='html') -> None

		Render the given template with the extra (optional) values and write it
		to the response.

		Args:

		template_path
			str, list - The template to render.

		extra_context
			dict - Template values to provide to the template.

		output
			str - The outputed page type.
			Only supports 'html'

		Return:

		None

		"""

		output_info = const.OUTPUT_TYPES[output]

		parsed	= urlparse.urlparse(self.request.url)

		get 	= self.request.get
		user	= self.user
		udata	= self.udata

		# We want to force the user to give themself a nickname
		# But it will fall into an infinate loop before the user can submit a name.
		if udata and not udata.nickname and not parsed.path.startswith('/first/'):
			self.redirect('/first/?continue=%s' % self.url)
			return

		cf_credit = ''
		cf_script = get('cf_script', '')
		use_custom_cf = False
		if cf_script:
			pass
		elif udata:
			if udata.use_custom_cf:
				use_custom_cf = True
				cf_script = udata.custom_cf_script
			elif udata.cf_script != 'disabled':
				cf_script = udata.cf_script
		else:
			cf_script = 'daze'
			
		if not use_custom_cf:	
			path = os.path.join('.', 'data', 'contextfree', '%s.txt' % cf_script.lower())	
			if cf_script and os.path.exists(path):	
				with open(path) as f:
					cf_credit = f.readline()
					cf_script = f.read()

		msg_count = None
		if udata:
			msg_count = counter.Counter('%sMessages' % udata.key_name).count

		# Allow forced message overrides
		msg = get('msg')
		if msg:
			self.flash.msg = msg

		context = {
			'cf_credit'	: cf_credit,
			'cf_script'	: cf_script,
			'debug'		: get('debug'),
			'flash'		: self.flash,
			'host_url'	: "%s://%s" % (parsed.scheme, parsed.hostname),
			'is_dev'	: utils.is_dev(),
			'login_url'	: users.create_login_url('/first/?continue=%s' % self.url),
			'logout_url': users.create_logout_url('/'),
			'msg_count'	: msg_count,
			'page_admin': users.is_current_user_admin(),
			'request'	: self.request,
			'design'	: get('design'),
			'theme'		: get('theme'),
			'udata'		: udata,
			'url'		: self.url,
			'user'		: user,
			'year'		: datetime.datetime.now().year
		}
		context.update(extra_context)
		context.update(self.context)

		if get('json', False) is False:
			renderer = TemplateRenderer(template_path, context, output)
			rendered = renderer.render()
		else:
			const.OUTPUT_TYPES['json']
			import simplejson
			rendered = simplejson.dumps(context, skipkeys=True).replace('\\n', '\n')

		self.response.headers['Content-Type'] = output_info['header']
		self.response.headers['Content-Length'] = str(len(rendered))
		self.response.out.write(rendered)
예제 #10
0
from common.utils import vars, is_dev
import boto3

url = "http://localhost:3002" if is_dev() else "https://gnothiai.com"


def send_mail(email, type, data):
    if is_dev(): return
    if type == 'forgot-password':
        subject = "Gnothi reset password"
        body = f"Click this link to reset your password: {url}/reset-password?token={data}"
    elif type == 'welcome':
        subject = "Welcome to Gnothi"
        body = f"Thank you for registering a Gnothi account! Start journaling away."
    elif type == 'action':
        subject = f"Gnothi: {data['category']}/{data['action']}"
        body = subject
    else:
        return

    ses = boto3.client('ses')
    ses.send_email(Source=vars.EMAIL_SES_EMAIL_SOURCE,
                   Destination={'ToAddresses': [email]},
                   Message={
                       'Subject': {
                           'Data': subject
                       },
                       'Body': {
                           'Text': {
                               'Data': body
                           }
예제 #11
0
import requests
from common.utils import vars, is_dev
from typing import Union
from pydantic import UUID4
import hashlib

DEBUG = is_dev()
def ga(uid: Union[str, UUID4], category: str, action: str):
    """
    I'm only tracking interesting server-side events right now (no cookies), I want to see what features
    are being used and important bits like sign-ups & book-thumbs. user-id is obfuscated
    https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#event
    """
    # actually don't care about uid, just need a unique identifier. Note this is
    # a 1-way hash (right?), so I can't even decrypt - just want unique per-feature track
    uid = str(uid).encode()  # to bytes
    uid = hashlib.sha256(uid).hexdigest()
    url = "https://ssl.google-analytics.com/"
    url += "debug/collect" if DEBUG else "collect"
    res = requests.post(url, params=dict(
        v=1,
        tid=vars.GA,
        cid=uid,
        t='event',
        ec=category,
        ea=action
    ))
    if DEBUG: print(res.json())
예제 #12
0
def sync_for(user):
    if is_dev(): return
    if not (user.habitica_user_id and user.habitica_api_token):
        return
    # https://habitica.com/apidoc/#api-Task-GetUserTasks
    logger.info("Calling Habitica")
    headers = {
        "Content-Type": "application/json",
        "x-api-user": user.habitica_user_id,
        "x-api-key": user.habitica_api_token,
        "x-client": f"{vars.HABIT_USER}-{vars.HABIT_APP}"
    }
    tasks = requests.get('https://habitica.com/api/v3/tasks/user',
                         headers=headers).json()['data']
    huser = requests.get(
        'https://habitica.com/api/v3/user?userFields=lastCron,needsCron',
        headers=headers).json()['data']

    lastCron = dparse(huser['lastCron'])
    logger.info("Habitica finished")

    fes = M.FieldEntry.get_day_entries(user.id, day=lastCron).all()

    f_map = {f.service_id: f for f in user.fields}
    fe_map = {fe.field_id: fe for fe in fes}
    t_map = {task['id']: task for task in tasks}

    # Remove Habitica-deleted tasks
    for f in user.fields:
        if f.service != 'habitica': continue
        if f.service_id not in t_map:
            db.session.delete(f)
    db.session.commit()

    # Add/update tasks from Habitica
    for task in tasks:
        # {id, text, type, value}
        # habit: {counterUp, counterDown}
        # daily:{checklist: [{completed}], completed, isDue}

        # only care about habits/dailies
        if task['type'] not in ['habit', 'daily']: continue

        f = f_map.get(task['id'], None)
        if not f:
            # Field doesn't exist here yet, add it.
            # TODO delete things here if deleted in habitica
            f = M.Field(service='habitica',
                        service_id=task['id'],
                        name=task['text'],
                        type='number')
            user.fields.append(f)
        # Text has changed on Habitica, update here
        if f.name != task['text']:
            f.name = task['text']

        db.session.commit()  # for f to have f.id

        value = 0.
        # Habit
        if task['type'] == 'habit':
            value = (task['counterUp'] or 0.) - (task['counterDown'] or 0.)
        # Daily
        else:
            value = 1. if task['completed'] \
                else 0. if not task['isDue'] \
                else -1.

            # With Checklist
            cl = task['checklist']
            if (not task['completed']) and any(c['completed'] for c in cl):
                value = sum(c['completed'] for c in cl) / len(cl)

        fe = fe_map.get(f.id, None)
        if fe:
            fe.value = value
        else:
            fe = M.FieldEntry(field_id=f.id, created_at=lastCron, value=value)
            user.field_entries.append(fe)
        db.session.commit()
        logger.info(task['text'] + " done")