<commit_before># -*- coding: utf-8 -*-
import traceback

import binascii
from http.cookies import SimpleCookie

import base64
import copy
import datetime

import json

import pytz
from pyramid.request import Request
from pyramid.response import Response
from pyramid.settings import asbool
from sqlalchemy.sql.expression import select, and_

from gengine.app.permissions import perm_own_update_user_infos, perm_global_update_user_infos, perm_global_delete_user, perm_own_delete_user, \
    perm_global_access_admin_ui, perm_global_register_device, perm_own_register_device, perm_global_read_messages, \
    perm_own_read_messages
from gengine.base.model import valid_timezone, exists_by_expr, update_connection
from gengine.base.errors import APIError
from pyramid.exceptions import NotFound
from pyramid.renderers import render
from pyramid.view import view_config
from pyramid.wsgi import wsgiapp2
from werkzeug import DebuggedApplication

from gengine.app.admin import adminapp
from gengine.app.formular import FormularEvaluationException
from gengine.app.model import (
    User,
    Achievement,
    Value,
    Variable,
    AuthUser, AuthToken, t_users, t_auth_users, t_auth_users_roles, t_auth_roles, t_auth_roles_permissions, UserDevice,
    t_user_device, t_user_messages, UserMessage)
from gengine.base.settings import get_settings
from gengine.metadata import DBSession
from gengine.wsgiutil import HTTPSProxied

@view_config(route_name='add_or_update_user', renderer='string', request_method="POST")
def add_or_update_user(request):
    """add a user and set its metadata"""

    user_id = int(request.matchdict["user_id"])

    if asbool(get_settings().get("enable_user_authentication", False)):
        #ensure that the user exists and we have the permission to update it
        may_update = request.has_perm(perm_global_update_user_infos) or request.has_perm(perm_own_update_user_infos) and request.user.id == user_id
        if not may_update:
            raise APIError(403, "forbidden", "You may not edit this user.")

        #if not exists_by_expr(t_users,t_users.c.id==user_id):
        #    raise APIError(403, "forbidden", "The user does not exist. As the user authentication is enabled, you need to create the AuthUser first.")


    lat=None
    if len(request.POST.get("lat",""))>0:
        lat = float(request.POST["lat"])
    
    lon=None
    if len(request.POST.get("lon",""))>0:
        lon = float(request.POST["lon"])
    
    friends=[]
    if len(request.POST.get("friends",""))>0:
        friends = [int(x) for x in request.POST["friends"].split(",")]
    
    groups=[]
    if len(request.POST.get("groups",""))>0:
        groups = [int(x) for x in request.POST["groups"].split(",")]
    
    timezone="UTC"
    if len(request.POST.get("timezone",""))>0:
        timezone = request.POST["timezone"]
    
    if not valid_timezone(timezone):
        timezone = 'UTC'
    
    country=None
    if len(request.POST.get("country",""))>0:
        country = request.POST["country"]
    
    region=None
    if len(request.POST.get("region",""))>0:
        region = request.POST["region"]
    
    city=None
    if len(request.POST.get("city",""))>0:
        city = request.POST["city"]

    language = None
    if len(request.POST.get("language", "")) > 0:
        language= request.POST["language"]

    additional_public_data = {}
    if len(request.POST.get("additional_public_data", "")) > 0:
        try:
            additional_public_data = json.loads(request.POST["additional_public_data"])
        except:
            additional_public_data = {}


    User.set_infos(user_id=user_id,
                   lat=lat,
                   lng=lon,
                   timezone=timezone,
                   country=country,
                   region=region,
                   city=city,
                   language=language,
                   friends=friends,
                   groups=groups,
                   additional_public_data = additional_public_data)
    return {"status": "OK", "user" : User.full_output(user_id)}

@view_config(route_name='delete_user', renderer='string', request_method="DELETE")
def delete_user(request):
    """delete a user completely"""
    user_id = int(request.matchdict["user_id"])

    if asbool(get_settings().get("enable_user_authentication", False)):
        # ensure that the user exists and we have the permission to update it
        may_delete = request.has_perm(perm_global_delete_user) or request.has_perm(perm_own_delete_user) and request.user.id == user_id
        if not may_delete:
            raise APIError(403, "forbidden", "You may not delete this user.")

    User.delete_user(user_id)
    return {"status": "OK"}

def _get_progress(achievements_for_user, requesting_user):

    achievements = Achievement.get_achievements_by_user_for_today(achievements_for_user)

    def ea(achievement, achievement_date, execute_triggers):
        try:
            return Achievement.evaluate(achievements_for_user, achievement["id"], achievement_date, execute_triggers=execute_triggers)
        except FormularEvaluationException as e:
            return { "error": "Cannot evaluate formular: " + e.message, "id" : achievement["id"] }
        except Exception as e:
            tb = traceback.format_exc()
            return { "error": tb, "id" : achievement["id"] }

    check = lambda x : x!=None and not "error" in x and (x["hidden"]==False or x["level"]>0)

    def may_view(achievement, requesting_user):
        if not asbool(get_settings().get("enable_user_authentication", False)):
            return True

        if achievement["view_permission"] == "everyone":
            return True
        if achievement["view_permission"] == "own" and achievements_for_user["id"] == requesting_user["id"]:
            return True
        return False

    evaluatelist = []
    now = datetime.datetime.now(pytz.timezone(achievements_for_user["timezone"]))
    for achievement in achievements:
        if may_view(achievement, requesting_user):
            achievement_dates = set()
            d = max(achievement["created_at"], achievements_for_user["created_at"]).replace(tzinfo=pytz.utc)
            dr = Achievement.get_datetime_for_evaluation_type(
                achievements_for_user["timezone"],
                achievement["evaluation"],
                dt=d
            )
            if dr == None:
                achievement_dates.add(None)
            else:
                while d<=now:
                    achievement_dates.add(dr)

                    if achievement["evaluation"] == "yearly":
                        d += datetime.timedelta(days=365)
                    elif achievement["evaluation"] == "monthly":
                        d += datetime.timedelta(days=28)
                    elif achievement["evaluation"] == "weekly":
                        d += datetime.timedelta(days=7)
                    elif achievement["evaluation"] == "daily":
                        d += datetime.timedelta(days=1)
                    else:
                        break # should not happen

                    dr = Achievement.get_datetime_for_evaluation_type(
                        achievements_for_user["timezone"],
                        achievement["evaluation"],
                        dt=d
                    )

            i=0
            for achievement_date in reversed(sorted(achievement_dates)):
                # We execute the goal triggers only for the newest and previous period, not for any periods longer ago
                # (To not send messages for very old things....)
                evaluatelist.append(ea(achievement, achievement_date, execute_triggers=(i == 0 or i == 1)))
                i += 1


    ret = {
        "achievements" : [<commit_msg>dont limit trigger execution when date is None<commit_after># -*- coding: utf-8 -*-
import traceback

import binascii
from http.cookies import SimpleCookie

import base64
import copy
import datetime

import json

import pytz
from pyramid.request import Request
from pyramid.response import Response
from pyramid.settings import asbool
from sqlalchemy.sql.expression import select, and_

from gengine.app.permissions import perm_own_update_user_infos, perm_global_update_user_infos, perm_global_delete_user, perm_own_delete_user, \
    perm_global_access_admin_ui, perm_global_register_device, perm_own_register_device, perm_global_read_messages, \
    perm_own_read_messages
from gengine.base.model import valid_timezone, exists_by_expr, update_connection
from gengine.base.errors import APIError
from pyramid.exceptions import NotFound
from pyramid.renderers import render
from pyramid.view import view_config
from pyramid.wsgi import wsgiapp2
from werkzeug import DebuggedApplication

from gengine.app.admin import adminapp
from gengine.app.formular import FormularEvaluationException
from gengine.app.model import (
    User,
    Achievement,
    Value,
    Variable,
    AuthUser, AuthToken, t_users, t_auth_users, t_auth_users_roles, t_auth_roles, t_auth_roles_permissions, UserDevice,
    t_user_device, t_user_messages, UserMessage)
from gengine.base.settings import get_settings
from gengine.metadata import DBSession
from gengine.wsgiutil import HTTPSProxied

@view_config(route_name='add_or_update_user', renderer='string', request_method="POST")
def add_or_update_user(request):
    """add a user and set its metadata"""

    user_id = int(request.matchdict["user_id"])

    if asbool(get_settings().get("enable_user_authentication", False)):
        #ensure that the user exists and we have the permission to update it
        may_update = request.has_perm(perm_global_update_user_infos) or request.has_perm(perm_own_update_user_infos) and request.user.id == user_id
        if not may_update:
            raise APIError(403, "forbidden", "You may not edit this user.")

        #if not exists_by_expr(t_users,t_users.c.id==user_id):
        #    raise APIError(403, "forbidden", "The user does not exist. As the user authentication is enabled, you need to create the AuthUser first.")


    lat=None
    if len(request.POST.get("lat",""))>0:
        lat = float(request.POST["lat"])
    
    lon=None
    if len(request.POST.get("lon",""))>0:
        lon = float(request.POST["lon"])
    
    friends=[]
    if len(request.POST.get("friends",""))>0:
        friends = [int(x) for x in request.POST["friends"].split(",")]
    
    groups=[]
    if len(request.POST.get("groups",""))>0:
        groups = [int(x) for x in request.POST["groups"].split(",")]
    
    timezone="UTC"
    if len(request.POST.get("timezone",""))>0:
        timezone = request.POST["timezone"]
    
    if not valid_timezone(timezone):
        timezone = 'UTC'
    
    country=None
    if len(request.POST.get("country",""))>0:
        country = request.POST["country"]
    
    region=None
    if len(request.POST.get("region",""))>0:
        region = request.POST["region"]
    
    city=None
    if len(request.POST.get("city",""))>0:
        city = request.POST["city"]

    language = None
    if len(request.POST.get("language", "")) > 0:
        language= request.POST["language"]

    additional_public_data = {}
    if len(request.POST.get("additional_public_data", "")) > 0:
        try:
            additional_public_data = json.loads(request.POST["additional_public_data"])
        except:
            additional_public_data = {}


    User.set_infos(user_id=user_id,
                   lat=lat,
                   lng=lon,
                   timezone=timezone,
                   country=country,
                   region=region,
                   city=city,
                   language=language,
                   friends=friends,
                   groups=groups,
                   additional_public_data = additional_public_data)
    return {"status": "OK", "user" : User.full_output(user_id)}

@view_config(route_name='delete_user', renderer='string', request_method="DELETE")
def delete_user(request):
    """delete a user completely"""
    user_id = int(request.matchdict["user_id"])

    if asbool(get_settings().get("enable_user_authentication", False)):
        # ensure that the user exists and we have the permission to update it
        may_delete = request.has_perm(perm_global_delete_user) or request.has_perm(perm_own_delete_user) and request.user.id == user_id
        if not may_delete:
            raise APIError(403, "forbidden", "You may not delete this user.")

    User.delete_user(user_id)
    return {"status": "OK"}

def _get_progress(achievements_for_user, requesting_user):

    achievements = Achievement.get_achievements_by_user_for_today(achievements_for_user)

    def ea(achievement, achievement_date, execute_triggers):
        try:
            return Achievement.evaluate(achievements_for_user, achievement["id"], achievement_date, execute_triggers=execute_triggers)
        except FormularEvaluationException as e:
            return { "error": "Cannot evaluate formular: " + e.message, "id" : achievement["id"] }
        except Exception as e:
            tb = traceback.format_exc()
            return { "error": tb, "id" : achievement["id"] }

    check = lambda x : x!=None and not "error" in x and (x["hidden"]==False or x["level"]>0)

    def may_view(achievement, requesting_user):
        if not asbool(get_settings().get("enable_user_authentication", False)):
            return True

        if achievement["view_permission"] == "everyone":
            return True
        if achievement["view_permission"] == "own" and achievements_for_user["id"] == requesting_user["id"]:
            return True
        return False

    evaluatelist = []
    now = datetime.datetime.now(pytz.timezone(achievements_for_user["timezone"]))
    for achievement in achievements:
        if may_view(achievement, requesting_user):
            achievement_dates = set()
            d = max(achievement["created_at"], achievements_for_user["created_at"]).replace(tzinfo=pytz.utc)
            dr = Achievement.get_datetime_for_evaluation_type(
                achievements_for_user["timezone"],
                achievement["evaluation"],
                dt=d
            )
            if dr == None:
                achievement_dates.add(None)
            else:
                while d<=now:
                    achievement_dates.add(dr)

                    if achievement["evaluation"] == "yearly":
                        d += datetime.timedelta(days=365)
                    elif achievement["evaluation"] == "monthly":
                        d += datetime.timedelta(days=28)
                    elif achievement["evaluation"] == "weekly":
                        d += datetime.timedelta(days=7)
                    elif achievement["evaluation"] == "daily":
                        d += datetime.timedelta(days=1)
                    else:
                        break # should not happen

                    dr = Achievement.get_datetime_for_evaluation_type(
                        achievements_for_user["timezone"],
                        achievement["evaluation"],
                        dt=d
                    )

            i=0
            for achievement_date in reversed(sorted(achievement_dates)):
                # We execute the goal triggers only for the newest and previous period, not for any periods longer ago
                # (To not send messages for very old things....)
                evaluatelist.append(ea(achievement, achievement_date, execute_triggers=(i == 0 or i == 1 or achievement_date == None)))
                i += 1


    ret = {
        "achievements" : [
{'fraction_non_alphanumeric': 0.10473687584129222, 'fraction_numerical': 0.004486891865906032, 'mean_word_length': 2.7112274024738343, 'pattern_counts': {'":': 18, '<': 5, '<?xml version=': 0, '>': 25, 'https://': 0, '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': '2444232', 'n_tokens_mistral': 4577, 'n_tokens_neox': 4411, 'n_words': 1016}