<commit_before>#!/usr/bin/env python
import rospy
import math
from autobot.msg import drive_param
from sensor_msgs.msg import LaserScan
from autobot.msg import pid_input
from autobot.msg import wall_dist
# from autobot.srv import AdjustWallDist
from autobot.srv import *

"""
TODO:
- [x] Decide if you want to hug right/left/or closest wall
    - Right wall hugged for now to simulate right side of road
- [ ] Send error left to hug left wall
"""

class PathConfig(object):
    __slots__ = ('wallToWatch', 'desiredTrajectory', 'velocity', 'pubRate')
    """
    wallToWatch: Set which wall to hug
    options: autobot.msg.wall_dist.WALL_LEFT
             autobot.msg.wall_dist.WALL_RIGHT
             autobot.msg.wall_dist.WALL_FRONT  #< probably won't be used
    """
    wallToWatch = autobot.msg.wall_dist.WALL_RIGHT
    desiredTrajectory = 0.5  # desired distance from the wall
    minFrontDist = 2.2       # minimum required distance in front of car
    velocity = 7.3           # velocity of drive
    pubRate = 0              # publish rate of node

errorPub = rospy.Publisher('error', pid_input, queue_size=10)
motorPub = rospy.Publisher('drive_parameters', drive_param, queue_size=10)

def HandleAdjustWallDist(req):
    """ Handler for adjusting wall hugging parameters

    Responds with wall_dist msg and a bool to verify that the
    service command has been accepted
    """
    global PathConfig

    print " wall {}".format(req.cmd.wall)
    print " dist {}".format(req.cmd.dist)

    resp = wall_dist()
    isValid = req.cmd.dist >= 0

    if isValid is True and req.cmd.wall is autobot.msg.wall_dist.WALL_RIGHT:
        PathConfig.wallToWatch = req.cmd.wall
        PathConfig.desiredTrajectory = req.cmd.dist
        resp.wall = PathConfig.wallToWatch
        resp.dist = PathConfig.desiredTrajectory

    return AdjustWallDistResponse(resp, isValid)

def getRange(data, theta):
    """ Find the index of the array that corresponds to angle theta.
    Return the lidar scan value at that index
    Do some error checking for NaN and absurd values
    data: the LidarScan data
    theta: the angle to return the distance for
    """
    car_theta = math.radians(theta) - math.pi / 2
    if car_theta > 3 * math.pi / 4:
        car_theta = 3 * math.pi / 4
    elif car_theta < -3 * math.pi / 4:
        car_theta = -3 * math.pi / 4

    float_index = (car_theta + 3 * math.pi / 4) / data.angle_increment
    index = int(float_index)
    return data.ranges[index]

def callback(data):
    global PathConfig

    frontDistance = getRange(data, 90)

    theta = 50  # PICK THIS ANGLE TO BE BETWEEN 0 AND 70 DEGREES

    thetaDistRight = getRange(data, theta)  # a
    rightDist = getRange(data, 0)  # b

    thetaDistLeft = getRange(data, 180-theta)  # aL
    leftDist = getRange(data, 180)  # bL

    if frontDistance < PathConfig.minFrontDist:
        # TURN
        print "Blocked!"
        driveParam = drive_param()
        if rightDist > leftDist:
            driveParam.angle = 90
            print "Turning Right"
        else:
            driveParam.angle = -90
            print "Turning Left"
        driveParam.velocity = PathConfig.velocity
        motorPub.publish(driveParam)
        return

    thetaRadsRight = math.radians(theta)  # aRads
    thetaRadsLeft = math.radians(130)     # bRads

    # alpha right
    carAngleRight = math.atan2(thetaDistRight * math.cos(thetaRadsRight) - rightDist,
                               thetaDistRight * math.sin(thetaRadsRight))

    # alpha left
    carAngleLeft = math.atan2(thetaDistLeft * math.cos(thetaRadsRight) - leftDist,
                              thetaDistLeft * math.sin(thetaRadsRight))

    carToWallRight = rightDist * math.cos(carAngleRight)  # AB
    carToWallLeft = leftDist * math.cos(carAngleLeft)     # ABL

    distTraveled = 1.0  # AC MAY NEED TO EDIT THIS VALUE

    # CD
    projectedDistRight = carToWallRight + distTraveled * math.sin(carAngleRight)

    # CDL
    projectedDistLeft = carToWallLeft + distTraveled * math.sin(carAngleLeft)

    """
    If too far from the wall:
        Turn right to get closer to it
        errorRight will be positive
    if too close to wall:
        Turn left to get further
        errorRight will be negative

    The error_ values are differences between projected future position
    and the distance to the wall
    """
    # ARE WE PROCESSING THIS ERROR CORRECTLY? GETS SENT TO PIDCONTROL.PY
    errorRight = projectedDistRight - PathConfig.desiredTrajectory
    errorLeft = projectedDistLeft - PathConfig.desiredTrajectory
    errorLeft *= -1

    print "carAngleRight {} carAngleLeft {}".format(carAngleRight,
                                                    carAngleLeft)
    print ("thetaDistRight {} thetaDistLeft {}\n"
           "rightDist {} leftDist {}").format(
        thetaDistRight,
        thetaDistLeft,
        rightDist,
        leftDist)

    print "carToWallRight {} carToWallLeft {}".format(
        carToWallRight,
        carToWallLeft)
    print "projectedDistRight {} projectedDistLeft {}".format(
        projectedDistRight,
        projectedDistLeft)

    print "errorRight {} errorLeft {}".format(errorRight, errorLeft)

    msg = pid_input()
    msg.pid_error = errorRight
    # msg.pid_error = errorLeft
    msg.pid_vel = PathConfig.velocity

    PathConfig.pubRate += 1
    if (PathConfig.pubRate % 10 == 0):
        PathConfig.pubRate = 0
        errorPub.publish(msg)

if __name__ == '__main__':
    print("Path finding node started")
    rospy.Service('adjustWallDist', AdjustWallDist, HandleAdjustWallDist)
    rospy.init_node('pathFinder', anonymous=True)
    rospy.Subscriber("scan", LaserScan, callback)
    rospy.spin()
<commit_msg>Add support for switching wall to hug via service call<commit_after>#!/usr/bin/env python
import rospy
import math
from autobot.msg import drive_param
from sensor_msgs.msg import LaserScan
from autobot.msg import pid_input
from autobot.msg import wall_dist
# from autobot.srv import AdjustWallDist
from autobot.srv import *

"""
TODO:
- [x] Decide if you want to hug right/left/or closest wall
    - Right wall hugged for now to simulate right side of road
    - Update: wall decision to be made by image processing node
- [x] Send error left to hug left wall
"""

class PathConfig(object):
    __slots__ = ('wallToWatch', 'desiredTrajectory', 'velocity', 'pubRate')
    """
    wallToWatch: Set which wall to hug
    options: autobot.msg.wall_dist.WALL_LEFT
             autobot.msg.wall_dist.WALL_RIGHT
             autobot.msg.wall_dist.WALL_FRONT  #< probably won't be used
    """
    wallToWatch = autobot.msg.wall_dist.WALL_RIGHT
    desiredTrajectory = 0.5  # desired distance from the wall
    minFrontDist = 2.2       # minimum required distance in front of car
    velocity = 7.3           # velocity of drive
    pubRate = 0              # publish rate of node

errorPub = rospy.Publisher('error', pid_input, queue_size=10)
motorPub = rospy.Publisher('drive_parameters', drive_param, queue_size=10)

def HandleAdjustWallDist(req):
    """ Handler for adjusting wall hugging parameters

    Responds with wall_dist msg and a bool to verify that the
    service command has been accepted
    """
    global PathConfig

    print " wall {}".format(req.cmd.wall)
    print " dist {}".format(req.cmd.dist)

    resp = wall_dist()
    isValid = req.cmd.dist >= 0

    if isValid is True and req.cmd.wall != autobot.msg.wall_dist.WALL_FRONT:
        """ only accept WALL_LEFT or WALL_RIGHT
        Service client can send an invalid wall or distance
        query current settings
        """
        PathConfig.wallToWatch = req.cmd.wall
        PathConfig.desiredTrajectory = req.cmd.dist
    else:
        isValid = False

    resp.wall = PathConfig.wallToWatch
    resp.dist = PathConfig.desiredTrajectory
    return AdjustWallDistResponse(resp, isValid)

def getRange(data, theta):
    """ Find the index of the array that corresponds to angle theta.
    Return the lidar scan value at that index
    Do some error checking for NaN and absurd values
    data: the LidarScan data
    theta: the angle to return the distance for
    """
    car_theta = math.radians(theta) - math.pi / 2
    if car_theta > 3 * math.pi / 4:
        car_theta = 3 * math.pi / 4
    elif car_theta < -3 * math.pi / 4:
        car_theta = -3 * math.pi / 4

    float_index = (car_theta + 3 * math.pi / 4) / data.angle_increment
    index = int(float_index)
    return data.ranges[index]

def callback(data):
    global PathConfig

    frontDistance = getRange(data, 90)

    theta = 50  # PICK THIS ANGLE TO BE BETWEEN 0 AND 70 DEGREES

    thetaDistRight = getRange(data, theta)  # a
    rightDist = getRange(data, 0)  # b

    thetaDistLeft = getRange(data, 180-theta)  # aL
    leftDist = getRange(data, 180)  # bL

    if frontDistance < PathConfig.minFrontDist:
        # TURN
        print "Blocked!"
        driveParam = drive_param()
        if rightDist > leftDist:
            driveParam.angle = 90
            print "Turning Right"
        else:
            driveParam.angle = -90
            print "Turning Left"
        driveParam.velocity = PathConfig.velocity
        motorPub.publish(driveParam)
        return

    thetaRadsRight = math.radians(theta)  # aRads
    thetaRadsLeft = math.radians(130)     # bRads

    # alpha right
    carAngleRight = math.atan2(thetaDistRight * math.cos(thetaRadsRight) - rightDist,
                               thetaDistRight * math.sin(thetaRadsRight))

    # alpha left
    carAngleLeft = math.atan2(thetaDistLeft * math.cos(thetaRadsRight) - leftDist,
                              thetaDistLeft * math.sin(thetaRadsRight))

    carToWallRight = rightDist * math.cos(carAngleRight)  # AB
    carToWallLeft = leftDist * math.cos(carAngleLeft)     # ABL

    distTraveled = 1.0  # AC MAY NEED TO EDIT THIS VALUE

    # CD
    projectedDistRight = carToWallRight + distTraveled * math.sin(carAngleRight)

    # CDL
    projectedDistLeft = carToWallLeft + distTraveled * math.sin(carAngleLeft)

    """
    If too far from the wall:
        Turn right to get closer to it
        errorRight will be positive
    if too close to wall:
        Turn left to get further
        errorRight will be negative

    The error_ values are differences between projected future position
    and the distance to the wall
    """
    # ARE WE PROCESSING THIS ERROR CORRECTLY? GETS SENT TO PIDCONTROL.PY
    errorRight = projectedDistRight - PathConfig.desiredTrajectory
    errorLeft = projectedDistLeft - PathConfig.desiredTrajectory
    errorLeft *= -1

    print "carAngleRight {} carAngleLeft {}".format(carAngleRight,
                                                    carAngleLeft)
    print ("thetaDistRight {} thetaDistLeft {}\n"
           "rightDist {} leftDist {}").format(
        thetaDistRight,
        thetaDistLeft,
        rightDist,
        leftDist)

    print "carToWallRight {} carToWallLeft {}".format(
        carToWallRight,
        carToWallLeft)
    print "projectedDistRight {} projectedDistLeft {}".format(
        projectedDistRight,
        projectedDistLeft)

    print "errorRight {} errorLeft {}".format(errorRight, errorLeft)

    msg = pid_input()
    if PathConfig.wallToWatch == autobot.msg.wall_dist.WALL_LEFT:
        msg.pid_error = errorLeft
    else:
        msg.pid_error = errorRight

    msg.pid_vel = PathConfig.velocity

    PathConfig.pubRate += 1
    if (PathConfig.pubRate % 10 == 0):
        PathConfig.pubRate = 0
        errorPub.publish(msg)

if __name__ == '__main__':
    print("Path finding node started")
    rospy.Service('adjustWallDist', AdjustWallDist, HandleAdjustWallDist)
    rospy.init_node('pathFinder', anonymous=True)
    rospy.Subscriber("scan", LaserScan, callback)
    rospy.spin()
<|endoftext|>


<commit_before>import numpy as np

def empty(shape, dtype=float, cphvb=True):
    return np.empty(shape, dtype, cphvb)

def ones(shape, dtype=float, cphvb=True):
    A = empty(shape, dtype, cphvb)
    A[:] = 1
    return A

def zeros(shape, dtype=float, cphvb=True):
    A = empty(shape, dtype, cphvb)
    A[:] = 0
    return A

def flatten(A):
    return A.reshape(np.multiply.reduce(np.asarray(A.shape)))

def diagonal(A,k=0):
    if A.ndim !=2 :
        raise Exception("diagonal only supports 2 dimensions\n")
    if k < 0:
        d = A[-k:,0]
    elif k > 0:
        d = A[0,k:]
    else:
        d = A[0]
    d.strides=(A.strides[0]+A.strides[1])
    return d

def diagflat(d,k=0):
    d = np.asarray(d)
    d = flatten(d)
    A = zeros((d.size,d.size), dtype=d.dtype, cphvb=d.cphvb)
    Ad = diagonal(A)
    Ad[:] = d
    return A

def diag(A,k=0):
    if A.ndim == 1:
        return diagflat(A,k)
    elif A.ndim == 2:
        return diagonal(A,k)
    else:
        raise ValueError("Input must be 1- or 2-d.")

def dot(A,B):
    if B.ndim == 1:
        return np.add.reduce(A*B,-1)
    if A.ndim == 1:
        return np.add.reduce(A*np.transpose(B),-1)
    return np.add.reduce(A[:,np.newaxis]*np.transpose(B),-1)
<commit_msg>Fixed bug in cphvbnumpy core where the function arguments was not pasted to the numpy array creation functions<commit_after>import numpy as np

def empty(shape, dtype=float, cphvb=True):
    return np.empty(shape, dtype=dtype, cphvb=cphvb)

def ones(shape, dtype=float, cphvb=True):
    A = empty(shape, dtype=dtype, cphvb=cphvb)
    A[:] = 1
    return A

def zeros(shape, dtype=float, cphvb=True):
    A = empty(shape, dtype=dtype, cphvb=cphvb)
    A[:] = 0
    return A

def flatten(A):
    return A.reshape(np.multiply.reduce(np.asarray(A.shape)))

def diagonal(A,k=0):
    if A.ndim !=2 :
        raise Exception("diagonal only supports 2 dimensions\n")
    if k < 0:
        d = A[-k:,0]
    elif k > 0:
        d = A[0,k:]
    else:
        d = A[0]
    d.strides=(A.strides[0]+A.strides[1])
    return d

def diagflat(d,k=0):
    d = np.asarray(d)
    d = flatten(d)
    A = zeros((d.size,d.size), dtype=d.dtype, cphvb=d.cphvb)
    Ad = diagonal(A)
    Ad[:] = d
    return A

def diag(A,k=0):
    if A.ndim == 1:
        return diagflat(A,k)
    elif A.ndim == 2:
        return diagonal(A,k)
    else:
        raise ValueError("Input must be 1- or 2-d.")

def dot(A,B):
    if B.ndim == 1:
        return np.add.reduce(A*B,-1)
    if A.ndim == 1:
        return np.add.reduce(A*np.transpose(B),-1)
    return np.add.reduce(A[:,np.newaxis]*np.transpose(B),-1)
<|endoftext|>


<commit_before>"""
Image interpolators using ndimage.
"""

__docformat__ = 'restructuredtext'

import os
import numpy as N

from scipy import ndimage
from neuroimaging.data_io.api import Cache

class ImageInterpolator(object):
    """
    TODO
    """

    def __init__(self, image, order=1, grid=None):
        """
        :Parameters:
            image : TODO
                TODO
            order : ``int``
                TODO
            grid : TODO
                TODO
        """
        if grid is None:
            self.grid = image.grid
        else:
            self.grid = grid
        self.image = image
        self.order = order
        self._prefilter()

    def _prefilter(self):
        if self.order > 1:
            data = ndimage.spline_filter(N.nan_to_num(self.image.readall()),
                                          self.order)
        else:
            data = N.nan_to_num(self.image.readall())

        if not hasattr(self, 'datafile'):
            self.datafile = file(Cache().tempfile(), mode='wb')
        else:
            self.datafile = file(self.datafile.name, 'wb')

        data = N.nan_to_num(data.astype(N.float64))
        data.tofile(self.datafile)
        datashape = data.shape
        dtype = data.dtype

        del(data)
        self.datafile.close()

        self.datafile = file(self.datafile.name)
        self.data = N.memmap(self.datafile.name, dtype=dtype,
                             mode='r+', shape=datashape)

    def __del__(self):
        if hasattr(self, 'datafile'):
            self.datafile.close()
            try:
                os.remove(self.datafile.name)
            except:
                pass

    def __call__(self, points):
        """
        :Parameters:
            points : TODO
                TODO

        :Returns: TODO
        """
        return self.evaluate(points)

    def evaluate(self, points):
        """
        :Parameters:
            points : TODO
                TODO

        :Returns: TODO
        """
        points = N.array(points, N.float64)
        output_shape = points.shape[1:]
        points.shape = (points.shape[0], N.product(output_shape))
        voxels = self.grid.mapping.inverse()(points)
        V = ndimage.map_coordinates(self.data,
                                     voxels,
                                     order=self.order,
                                     prefilter=False)

        V.shape = output_shape
        return V

    def resample(self, grid, mapping=None, **keywords):
        """
        Using an ImageInterpolator, resample an Image on the range
        of a grid, applying an optional mapping (taking
        keyword arguments ``keywords``) between the output
        coordinates of grid and self.image.grid.

        :Parameters:
            grid : TODO
                TODO
            mapping : TODO
                TODO
            keywords : ``dict``
                TODO

        :Returns: TODO
        """

        points = grid.range()
        if mapping is not None:
            points = mapping(points, **keywords)
        return self.evaluate(points)
<commit_msg>BUG: Update interpolation code so it works with new image class.<commit_after>"""
Image interpolators using ndimage.
"""

__docformat__ = 'restructuredtext'

import os
import numpy as np

from scipy import ndimage
from neuroimaging.data_io.api import Cache

class ImageInterpolator(object):
    """
    TODO
    """

    def __init__(self, image, order=1, grid=None):
        """
        :Parameters:
            image : TODO
                TODO
            order : ``int``
                TODO
            grid : TODO
                TODO
        """
        if grid is None:
            self.grid = image.grid
        else:
            self.grid = grid
        self.image = image
        self.order = order
        self._prefilter()

    def _prefilter(self):
        if self.order > 1:
            data = ndimage.spline_filter(np.nan_to_num(np.asarray(self.image)),
                                          self.order)
        else:
            data = np.nan_to_num(np.asarray(self.image))

        if not hasattr(self, 'datafile'):
            self.datafile = file(Cache().tempfile(), mode='wb')
        else:
            self.datafile = file(self.datafile.name, 'wb')

        data = np.nan_to_num(data.astype(np.float64))
        data.tofile(self.datafile)
        datashape = data.shape
        dtype = data.dtype

        del(data)
        self.datafile.close()

        self.datafile = file(self.datafile.name)
        self.data = np.memmap(self.datafile.name, dtype=dtype,
                             mode='r+', shape=datashape)

    def __del__(self):
        if hasattr(self, 'datafile'):
            self.datafile.close()
            try:
                os.remove(self.datafile.name)
            except:
                pass

    def __call__(self, points):
        """
        :Parameters:
            points : TODO
                TODO

        :Returns: TODO
        """
        return self.evaluate(points)

    def evaluate(self, points):
        """
        :Parameters:
            points : TODO
                TODO

        :Returns: TODO
        """
        points = np.array(points, np.float64)
        output_shape = points.shape[1:]
        points.shape = (points.shape[0], np.product(output_shape))
        voxels = self.grid.mapping.inverse()(points)
        V = ndimage.map_coordinates(self.data,
                                     voxels,
                                     order=self.order,
                                     prefilter=False)

        V.shape = output_shape
        return V

    def resample(self, grid, mapping=None, **keywords):
        """
        Using an ImageInterpolator, resample an Image on the range
        of a grid, applying an optional mapping (taking
        keyword arguments ``keywords``) between the output
        coordinates of grid and self.image.grid.

        :Parameters:
            grid : TODO
                TODO
            mapping : TODO
                TODO
            keywords : ``dict``
                TODO

        :Returns: TODO
        """

        points = grid.range()
        if mapping is not None:
            points = mapping(points, **keywords)
        return self.evaluate(points)
<|endoftext|>


<commit_before>import os
from shutil import copy2

class PrivilegeException(Exception):
    def __init__(self, value):
        self.paramater = value
    def __str__(self):
        return str(self.paramater)

def install(package):
    pip.main(['install', package])

def main():
    if os.geteuid() is not 0:
        raise PrivilegeException("You must have root privileges to run this install script.")

    print("Checking dependencies...")
    try:
        import colorama
    except ImportError:
        try:
            import pip
        except ImportError:
            print("pip must be installed for this script to function.")
            exit(-1)
        print("Required module [colorama] was not found. Installing via pip.")
        install('colorama')

    print("Copying files...")
    path = '/opt/wr'
    os.mkdir(path)
    copy2('./main.py', path)
    copy2('./joblib.py', path)
    copy2('./auxiliary.py', path)

    print("Creating symlink...")
    os.symlink('/opt/wr/main.py', '/usr/local/bin/wr')
    print("Successfully installed!")

if __name__ == '__main__':
    main()
<commit_msg>improved pip install message<commit_after>import os
from shutil import copy2

class PrivilegeException(Exception):
    def __init__(self, value):
        self.paramater = value
    def __str__(self):
        return str(self.paramater)

PIP_STRING = \
"""pip must be installed for this script to function!

debian-based:   apt install python3-pip
arch-based:     pacman -S python-pip
redhat-based:   yum install python-pip

If not listed, check your favorite search engine."""

def install(package):
    pip.main(['install', package])

def main():
    if os.geteuid() is not 0:
        raise PrivilegeException("You must have root privileges to run this install script.")

    print("Checking dependencies...")
    try:
        import colorama
    except ImportError:
        try:
            import pip
        except ImportError:
            print(PIP_STRING)
            exit(-1)
        print("Required module [colorama] was not found. Installing via pip.")
        install('colorama')

    print("Copying files...")
    path = '/opt/wr'
    os.mkdir(path)
    copy2('./main.py', path)
    copy2('./joblib.py', path)
    copy2('./auxiliary.py', path)

    print("Creating symlink...")
    os.symlink('/opt/wr/main.py', '/usr/local/bin/wr')
    print("Successfully installed!")

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>from collections import defaultdict
from datetime import datetime, timedelta

import pytz

from django.template import TemplateDoesNotExist
from django.template.loader import render_to_string

from casexml.apps.phone.models import OTARestoreCommCareUser
from dimagi.utils.dates import DateSpan
from dimagi.utils.decorators.memoized import memoized
from dimagi.utils.parsing import string_to_datetime

from corehq.apps.app_manager.dbaccessors import get_app
from corehq.apps.app_manager.fixtures.mobile_ucr import ReportFixturesProvider
from corehq.apps.app_manager.models import ReportModule
from corehq.apps.locations.dbaccessors import (
    get_user_ids_from_primary_location_ids,
    get_users_location_ids,
    get_users_by_location_id,
)
from corehq.apps.locations.models import SQLLocation
from corehq.apps.reports.analytics.esaccessors import (
    get_last_submission_time_for_users,
    get_last_form_submissions_by_user,
)
from corehq.util.quickcache import quickcache
from custom.icds.const import (
    CHILDREN_WEIGHED_REPORT_ID,
    DAYS_AWC_OPEN_REPORT_ID,
    HOME_VISIT_REPORT_ID,
    SUPERVISOR_APP_ID,
    THR_REPORT_ID,
    VHND_SURVEY_XMLNS,
)

DEFAULT_LANGUAGE = 'hin'

REPORT_IDS = [
    HOME_VISIT_REPORT_ID,
    THR_REPORT_ID,
    CHILDREN_WEIGHED_REPORT_ID,
    DAYS_AWC_OPEN_REPORT_ID,
]

@quickcache(['domain'], timeout=4 * 60 * 60, memoize_timeout=4 * 60 * 60)
def get_report_configs(domain):
    app = get_app(domain, SUPERVISOR_APP_ID, latest=True)
    return {
        report_config.report_id: report_config
        for module in app.modules if isinstance(module, ReportModule)
        for report_config in module.report_configs
        if report_config.report_id in REPORT_IDS
    }

@quickcache(['domain', 'report_id', 'ota_user.user_id'], timeout=12 * 60 * 60)
def get_report_fixture_for_user(domain, report_id, ota_user):
    """
    :param domain: the domain
    :param report_id: the index to the result from get_report_configs()
    :param ota_user: the OTARestoreCommCareUser for which to get the report fixture
    """
    return ReportFixturesProvider.report_config_to_fixture(
        get_report_configs(domain)[report_id], ota_user
    )

class IndicatorError(Exception):
    pass

class SMSIndicator(object):
    # The name of the template to be used when rendering the message(s) to be sent
    # This should not be the full path, just the name of the file, since the path
    # is determined at runtime by language code
    template = None

    # The domain this indicator is being run in
    domain = None

    # The user the indicator is being run for
    # For AWWIndicator, this is the AWW CommCareUser
    # For LSIndicator, this is the LS CommCareUser
    user = None

    def __init__(self, domain, user):
        self.domain = domain
        self.user = user

    @property
    @memoized
    def timezone(self):
        return pytz.timezone('Asia/Kolkata')

    @property
    @memoized
    def now(self):
        return datetime.now(tz=self.timezone)

    def get_messages(self, language_code=None):
        """
        Should return a list of messages that should be sent.
        """
        raise NotImplementedError()

    def render_template(self, context, language_code=None):
        if not language_code:
            return self._render_template(context, DEFAULT_LANGUAGE)

        try:
            return self._render_template(context, language_code)
        except TemplateDoesNotExist:
            return self._render_template(context, DEFAULT_LANGUAGE)

    def _render_template(self, context, language_code):
        template_name = 'icds/messaging/indicators/%s/%s' % (language_code, self.template)
        return render_to_string(template_name, context).strip()

class AWWIndicator(SMSIndicator):
    @property
    @memoized
    def supervisor(self):
        supervisor_location = self.user.sql_location.parent
        return get_users_by_location_id(self.domain, supervisor_location.location_id).first()

class LSIndicator(SMSIndicator):
    @property
    @memoized
    def child_locations(self):
        return self.user.sql_location.child_locations()

    @property
    @memoized
    def awc_locations(self):
        return {l.location_id: l.name for l in self.child_locations}

    @property
    @memoized
    def locations_by_user_id(self):
        return get_user_ids_from_primary_location_ids(self.domain, set(self.awc_locations))

    @property
    @memoized
    def aww_user_ids(self):
        return set(self.locations_by_user_id.keys())

    @property
    @memoized
    def user_ids_by_location_id(self):
        user_ids_by_location_id = defaultdict(set)
        for u_id, loc_id in self.locations_by_user_id.items():
            user_ids_by_location_id[loc_id].add(u_id)

        return user_ids_by_location_id

    def location_names_from_user_id(self, user_ids):
        loc_ids = {self.locations_by_user_id.get(u) for u in user_ids}
        return {self.awc_locations[l] for l in loc_ids}

class AWWAggregatePerformanceIndicator(AWWIndicator):
    template = 'aww_aggregate_performance.txt'

    def get_value_from_fixture(self, fixture, attribute):
        xpath = './rows/row[@is_total_row="False"]'
        rows = fixture.findall(xpath)
        location_name = self.user.sql_location.name
        for row in rows:
            owner_id = row.find('./column[@id="owner_id"]')
            if owner_id.text == location_name:
                try:
                    return row.find('./column[@id="{}"]'.format(attribute)).text
                except:
                    raise IndicatorError(
                        "Attribute {} not found in restore for AWC {}".format(attribute, location_name)
                    )

        raise IndicatorError("AWC {} not found in the restore".format(location_name))

    def get_messages(self, language_code=None):
        agg_perf = LSAggregatePerformanceIndicator(self.domain, self.supervisor)

        visits = self.get_value_from_fixture(agg_perf.visits_fixture, 'count')
        thr_gte_21 = self.get_value_from_fixture(agg_perf.thr_fixture, 'open_ccs_thr_gte_21')
        thr_count = self.get_value_from_fixture(agg_perf.thr_fixture, 'open_count')
        num_weigh = self.get_value_from_fixture(agg_perf.weighed_fixture, 'open_weighed')
        num_weigh_avail = self.get_value_from_fixture(agg_perf.weighed_fixture, 'open_count')
        num_days_open = self.get_value_from_fixture(agg_perf.days_open_fixture, 'awc_opened_count')

        context = {
            "visits": visits,
            "thr_distribution": "{} / {}".format(thr_gte_21, thr_count),
            "children_weighed": "{} / {}".format(num_weigh, num_weigh_avail),
            "days_open": num_days_open,
        }

        return [self.render_template(context, language_code=language_code)]

class AWWSubmissionPerformanceIndicator(AWWIndicator):
    template = 'aww_no_submissions.txt'
    last_submission_date = None

    def __init__(self, domain, user):
        super(AWWSubmissionPerformanceIndicator, self).__init__(domain, user)

        result = get_last_submission_time_for_users(self.domain, [self.user.get_id], self.get_datespan())
        self.last_submission_date = result.get(self.user.get_id)

    def get_datespan(self):
        today = datetime(self.now.year, self.now.month, self.now.day)
        end_date = today + timedelta(days=1)
        start_date = today - timedelta(days=30)
        return DateSpan(start_date, end_date, timezone=self.timezone)

    def get_messages(self, language_code=None):
        more_than_one_week = False
        more_than_one_month = False

        if not self.last_submission_date:
            more_than_one_month = True
        else:
            days_since_submission = (self.now.date() - self.last_submission_date).days
            if days_since_submission > 7:
                more_than_one_week = True

        if more_than_one_week or more_than_one_month:
            context = {
                'more_than_one_week': more_than_one_week,
                'more_than_one_month': more_than_one_month,
                'awc': self.user.sql_location.name,
            }
            return [self.render_template(context, language_code=language_code)]

        return []

class LSSubmissionPerformanceIndicator(LSIndicator):
    template = 'ls_no_submissions.txt'

    def __init__(self, domain, user):
        super(LSSubmissionPerformanceIndicator, self).__init__(domain, user)

        self.last_submission_dates = get_last_submission_time_for_users(
            self.domain, self.aww_user_ids, self.get_datespan()
        )

    def get_datespan(self):
        today = datetime(self.now.year, self.now.month, self.now.day)
        end_date = today + timedelta(days=1)
        start_date = today - timedelta(days=30)
        return DateSpan(start_date, end_date, timezone=self.timezone)

    def get_messages(self, language_code=None):
        messages = []
        one_week_user_ids = []
        one_month_user_ids = []

        now_date = self.now.date()
        for user_id in self.aww_user_ids:
            last_sub_date = self.last_submission_dates.get(user_id)
            if not last_sub_date:
                one_month_user_ids.append(user_id)
            else:
                days_since_submission = (now_date - last_sub_date).days
                if days_since_submission > 7:
                    one_week_user_ids.append(user_id)

        if one_week_user_ids:
            one_week_loc_names = self.location_names_from_user_id(one_week_user_ids)
            week_context = {'location_names': ', '.join(one_week_loc_names), 'timeframe': 'week'}
            messages.append(self.render_template(week_context, language_code=language_code))

        if one_month_user_ids:
            one_month_loc_names = self.location_names_from_user_id(one_month_user_ids)
            month_context = {'location_names': ','.join(one_month_loc_names), 'timeframe': 'month'}
            messages.append(self.render_template(month_context, language_code=language_code))

        return messages

class LSVHNDSurveyIndicator(LSIndicator):
    template = 'ls_vhnd_survey.txt'

    def __init__(self, domain, user):
        super(LSVHNDSurveyIndicator, self).__init__(domain, user)

        self.forms = get_last_form_submissions_by_user(
            domain, self.aww_user_ids, xmlns=VHND_SURVEY_XMLNS
        )

    def get_messages(self, language_code=None):
        def convert_to_date(date):
            return string_to_datetime(date).date() if date else None

        now_date = self.now.date()
        user_ids_with_forms_in_time_frame = set()
        for user_id, forms in self.forms.items():
            vhnd_date = convert_to_date(forms[0]['form']['vhsnd_date_past_month'])
            if (now_date - vhnd_date).days < 37:
                user_ids_with_forms_in_time_frame.add(user_id)

        awc_ids = {
            loc
            for loc, user_ids in self.user_ids_by_location_id.items()
            if user_ids.isdisjoint(user_ids_with_forms_in_time_frame)
        }
        messages = []

        if awc_ids:
            awc_names = {self.awc_locations[awc] for awc in awc_ids}
            context = {'location_names': ', '.join(awc_names)}
            messages.append(self.render_template(context, language_code=language_code))

        return messages

class LSAggregatePerformanceIndicator(LSIndicator):
    template = 'ls_aggregate_performance.txt'

    @property
    @memoized
    def restore_user(self):
        return OTARestoreCommCareUser(self.domain, self.user)

    def get_report_fixture(self, report_id):
        return get_report_fixture_for_user(self.domain, report_id, self.restore_user)

    def clear_caches(self):
        get_report_configs.clear(self.domain)
        for report_id in REPORT_IDS:
            get_report_fixture_for_user.clear(self.domain, report_id, self.restore_user)

    @property
    @memoized
    def visits_fixture(self):
        return self.get_report_fixture(HOME_VISIT_REPORT_ID)

    @property
    @memoized
    def thr_fixture(self):
        return self.get_report_fixture(THR_REPORT_ID)

    @property
    @memoized
    def weighed_fixture(self):
        return self.get_report_fixture(CHILDREN_WEIGHED_REPORT_ID)

    @property
    @memoized
    def days_open_fixture(self):
        return self.get_report_fixture(DAYS_AWC_OPEN_REPORT_ID)

    def get_value_from_fixture(self, fixture, attribute):
        xpath = './rows/row[@is_total_row="True"]/column[@id="{}"]'.format(attribute)
        try:
            return fixture.findall(xpath)[0].text
        except:
            raise IndicatorError("{} not found in fixture {} for user {}".format(
                attribute, fixture, self.user.get_id
            ))

    def get_messages(self, language_code=None):
        visit_on_time = self.get_value_from_fixture(self.visits_fixture, 'visit_on_time')
        visits = self.get_value_from_fixture(self.visits_fixture, 'count')
        thr_gte_21 = self.get_value_from_fixture(self.thr_fixture, 'open_ccs_thr_gte_21')
        thr_count = self.get_value_from_fixture(self.thr_fixture, 'open_count')
        num_weigh = self.get_value_from_fixture(self.weighed_fixture, 'open_weighed')
        num_weigh_avail = self.get_value_from_fixture(self.weighed_fixture, 'open_count')
        num_days_open = int(self.get_value_from_fixture(self.days_open_fixture, 'awc_opened_count'))
        num_awc_locations = len(self.days_open_fixture.findall('./rows/row[@is_total_row="False"]'))
        if num_awc_locations:
            avg_days_open = int(round(1.0 * num_days_open / num_awc_locations))
        else:
            # catch div by 0
            avg_days_open = 0

        context = {
            "visits": "{} / {}".format(visit_on_time, visits),
            "thr_distribution": "{} / {}".format(thr_gte_21, thr_count),
            "children_weighed": "{} / {}".format(num_weigh, num_weigh_avail),
            "days_open": "{}".format(avg_days_open),
        }

        return [self.render_template(context, language_code=language_code)]
<commit_msg>Handle supervisor misconfiguration<commit_after>from collections import defaultdict
from datetime import datetime, timedelta

import pytz

from django.template import TemplateDoesNotExist
from django.template.loader import render_to_string

from casexml.apps.phone.models import OTARestoreCommCareUser
from dimagi.utils.dates import DateSpan
from dimagi.utils.decorators.memoized import memoized
from dimagi.utils.parsing import string_to_datetime

from corehq.apps.app_manager.dbaccessors import get_app
from corehq.apps.app_manager.fixtures.mobile_ucr import ReportFixturesProvider
from corehq.apps.app_manager.models import ReportModule
from corehq.apps.locations.dbaccessors import (
    get_user_ids_from_primary_location_ids,
    get_users_location_ids,
    get_users_by_location_id,
)
from corehq.apps.locations.models import SQLLocation
from corehq.apps.reports.analytics.esaccessors import (
    get_last_submission_time_for_users,
    get_last_form_submissions_by_user,
)
from corehq.util.quickcache import quickcache
from custom.icds.const import (
    CHILDREN_WEIGHED_REPORT_ID,
    DAYS_AWC_OPEN_REPORT_ID,
    HOME_VISIT_REPORT_ID,
    SUPERVISOR_APP_ID,
    THR_REPORT_ID,
    VHND_SURVEY_XMLNS,
)

DEFAULT_LANGUAGE = 'hin'

REPORT_IDS = [
    HOME_VISIT_REPORT_ID,
    THR_REPORT_ID,
    CHILDREN_WEIGHED_REPORT_ID,
    DAYS_AWC_OPEN_REPORT_ID,
]

@quickcache(['domain'], timeout=4 * 60 * 60, memoize_timeout=4 * 60 * 60)
def get_report_configs(domain):
    app = get_app(domain, SUPERVISOR_APP_ID, latest=True)
    return {
        report_config.report_id: report_config
        for module in app.modules if isinstance(module, ReportModule)
        for report_config in module.report_configs
        if report_config.report_id in REPORT_IDS
    }

@quickcache(['domain', 'report_id', 'ota_user.user_id'], timeout=12 * 60 * 60)
def get_report_fixture_for_user(domain, report_id, ota_user):
    """
    :param domain: the domain
    :param report_id: the index to the result from get_report_configs()
    :param ota_user: the OTARestoreCommCareUser for which to get the report fixture
    """
    return ReportFixturesProvider.report_config_to_fixture(
        get_report_configs(domain)[report_id], ota_user
    )

class IndicatorError(Exception):
    pass

class SMSIndicator(object):
    # The name of the template to be used when rendering the message(s) to be sent
    # This should not be the full path, just the name of the file, since the path
    # is determined at runtime by language code
    template = None

    # The domain this indicator is being run in
    domain = None

    # The user the indicator is being run for
    # For AWWIndicator, this is the AWW CommCareUser
    # For LSIndicator, this is the LS CommCareUser
    user = None

    def __init__(self, domain, user):
        self.domain = domain
        self.user = user

    @property
    @memoized
    def timezone(self):
        return pytz.timezone('Asia/Kolkata')

    @property
    @memoized
    def now(self):
        return datetime.now(tz=self.timezone)

    def get_messages(self, language_code=None):
        """
        Should return a list of messages that should be sent.
        """
        raise NotImplementedError()

    def render_template(self, context, language_code=None):
        if not language_code:
            return self._render_template(context, DEFAULT_LANGUAGE)

        try:
            return self._render_template(context, language_code)
        except TemplateDoesNotExist:
            return self._render_template(context, DEFAULT_LANGUAGE)

    def _render_template(self, context, language_code):
        template_name = 'icds/messaging/indicators/%s/%s' % (language_code, self.template)
        return render_to_string(template_name, context).strip()

class AWWIndicator(SMSIndicator):
    @property
    @memoized
    def supervisor(self):
        """
        Returns None if there is a misconfiguration (i.e., if the AWW's location
        has no parent location, or if there are no users at the parent location).
        """
        supervisor_location = self.user.sql_location.parent
        if supervisor_location is None:
            return None

        return get_users_by_location_id(self.domain, supervisor_location.location_id).first()

class LSIndicator(SMSIndicator):
    @property
    @memoized
    def child_locations(self):
        return self.user.sql_location.child_locations()

    @property
    @memoized
    def awc_locations(self):
        return {l.location_id: l.name for l in self.child_locations}

    @property
    @memoized
    def locations_by_user_id(self):
        return get_user_ids_from_primary_location_ids(self.domain, set(self.awc_locations))

    @property
    @memoized
    def aww_user_ids(self):
        return set(self.locations_by_user_id.keys())

    @property
    @memoized
    def user_ids_by_location_id(self):
        user_ids_by_location_id = defaultdict(set)
        for u_id, loc_id in self.locations_by_user_id.items():
            user_ids_by_location_id[loc_id].add(u_id)

        return user_ids_by_location_id

    def location_names_from_user_id(self, user_ids):
        loc_ids = {self.locations_by_user_id.get(u) for u in user_ids}
        return {self.awc_locations[l] for l in loc_ids}

class AWWAggregatePerformanceIndicator(AWWIndicator):
    template = 'aww_aggregate_performance.txt'

    def get_value_from_fixture(self, fixture, attribute):
        xpath = './rows/row[@is_total_row="False"]'
        rows = fixture.findall(xpath)
        location_name = self.user.sql_location.name
        for row in rows:
            owner_id = row.find('./column[@id="owner_id"]')
            if owner_id.text == location_name:
                try:
                    return row.find('./column[@id="{}"]'.format(attribute)).text
                except:
                    raise IndicatorError(
                        "Attribute {} not found in restore for AWC {}".format(attribute, location_name)
                    )

        raise IndicatorError("AWC {} not found in the restore".format(location_name))

    def get_messages(self, language_code=None):
        if self.supervisor is None:
            return []

        agg_perf = LSAggregatePerformanceIndicator(self.domain, self.supervisor)

        visits = self.get_value_from_fixture(agg_perf.visits_fixture, 'count')
        thr_gte_21 = self.get_value_from_fixture(agg_perf.thr_fixture, 'open_ccs_thr_gte_21')
        thr_count = self.get_value_from_fixture(agg_perf.thr_fixture, 'open_count')
        num_weigh = self.get_value_from_fixture(agg_perf.weighed_fixture, 'open_weighed')
        num_weigh_avail = self.get_value_from_fixture(agg_perf.weighed_fixture, 'open_count')
        num_days_open = self.get_value_from_fixture(agg_perf.days_open_fixture, 'awc_opened_count')

        context = {
            "visits": visits,
            "thr_distribution": "{} / {}".format(thr_gte_21, thr_count),
            "children_weighed": "{} / {}".format(num_weigh, num_weigh_avail),
            "days_open": num_days_open,
        }

        return [self.render_template(context, language_code=language_code)]

class AWWSubmissionPerformanceIndicator(AWWIndicator):
    template = 'aww_no_submissions.txt'
    last_submission_date = None

    def __init__(self, domain, user):
        super(AWWSubmissionPerformanceIndicator, self).__init__(domain, user)

        result = get_last_submission_time_for_users(self.domain, [self.user.get_id], self.get_datespan())
        self.last_submission_date = result.get(self.user.get_id)

    def get_datespan(self):
        today = datetime(self.now.year, self.now.month, self.now.day)
        end_date = today + timedelta(days=1)
        start_date = today - timedelta(days=30)
        return DateSpan(start_date, end_date, timezone=self.timezone)

    def get_messages(self, language_code=None):
        more_than_one_week = False
        more_than_one_month = False

        if not self.last_submission_date:
            more_than_one_month = True
        else:
            days_since_submission = (self.now.date() - self.last_submission_date).days
            if days_since_submission > 7:
                more_than_one_week = True

        if more_than_one_week or more_than_one_month:
            context = {
                'more_than_one_week': more_than_one_week,
                'more_than_one_month': more_than_one_month,
                'awc': self.user.sql_location.name,
            }
            return [self.render_template(context, language_code=language_code)]

        return []

class LSSubmissionPerformanceIndicator(LSIndicator):
    template = 'ls_no_submissions.txt'

    def __init__(self, domain, user):
        super(LSSubmissionPerformanceIndicator, self).__init__(domain, user)

        self.last_submission_dates = get_last_submission_time_for_users(
            self.domain, self.aww_user_ids, self.get_datespan()
        )

    def get_datespan(self):
        today = datetime(self.now.year, self.now.month, self.now.day)
        end_date = today + timedelta(days=1)
        start_date = today - timedelta(days=30)
        return DateSpan(start_date, end_date, timezone=self.timezone)

    def get_messages(self, language_code=None):
        messages = []
        one_week_user_ids = []
        one_month_user_ids = []

        now_date = self.now.date()
        for user_id in self.aww_user_ids:
            last_sub_date = self.last_submission_dates.get(user_id)
            if not last_sub_date:
                one_month_user_ids.append(user_id)
            else:
                days_since_submission = (now_date - last_sub_date).days
                if days_since_submission > 7:
                    one_week_user_ids.append(user_id)

        if one_week_user_ids:
            one_week_loc_names = self.location_names_from_user_id(one_week_user_ids)
            week_context = {'location_names': ', '.join(one_week_loc_names), 'timeframe': 'week'}
            messages.append(self.render_template(week_context, language_code=language_code))

        if one_month_user_ids:
            one_month_loc_names = self.location_names_from_user_id(one_month_user_ids)
            month_context = {'location_names': ','.join(one_month_loc_names), 'timeframe': 'month'}
            messages.append(self.render_template(month_context, language_code=language_code))

        return messages

class LSVHNDSurveyIndicator(LSIndicator):
    template = 'ls_vhnd_survey.txt'

    def __init__(self, domain, user):
        super(LSVHNDSurveyIndicator, self).__init__(domain, user)

        self.forms = get_last_form_submissions_by_user(
            domain, self.aww_user_ids, xmlns=VHND_SURVEY_XMLNS
        )

    def get_messages(self, language_code=None):
        def convert_to_date(date):
            return string_to_datetime(date).date() if date else None

        now_date = self.now.date()
        user_ids_with_forms_in_time_frame = set()
        for user_id, forms in self.forms.items():
            vhnd_date = convert_to_date(forms[0]['form']['vhsnd_date_past_month'])
            if (now_date - vhnd_date).days < 37:
                user_ids_with_forms_in_time_frame.add(user_id)

        awc_ids = {
            loc
            for loc, user_ids in self.user_ids_by_location_id.items()
            if user_ids.isdisjoint(user_ids_with_forms_in_time_frame)
        }
        messages = []

        if awc_ids:
            awc_names = {self.awc_locations[awc] for awc in awc_ids}
            context = {'location_names': ', '.join(awc_names)}
            messages.append(self.render_template(context, language_code=language_code))

        return messages

class LSAggregatePerformanceIndicator(LSIndicator):
    template = 'ls_aggregate_performance.txt'

    @property
    @memoized
    def restore_user(self):
        return OTARestoreCommCareUser(self.domain, self.user)

    def get_report_fixture(self, report_id):
        return get_report_fixture_for_user(self.domain, report_id, self.restore_user)

    def clear_caches(self):
        get_report_configs.clear(self.domain)
        for report_id in REPORT_IDS:
            get_report_fixture_for_user.clear(self.domain, report_id, self.restore_user)

    @property
    @memoized
    def visits_fixture(self):
        return self.get_report_fixture(HOME_VISIT_REPORT_ID)

    @property
    @memoized
    def thr_fixture(self):
        return self.get_report_fixture(THR_REPORT_ID)

    @property
    @memoized
    def weighed_fixture(self):
        return self.get_report_fixture(CHILDREN_WEIGHED_REPORT_ID)

    @property
    @memoized
    def days_open_fixture(self):
        return self.get_report_fixture(DAYS_AWC_OPEN_REPORT_ID)

    def get_value_from_fixture(self, fixture, attribute):
        xpath = './rows/row[@is_total_row="True"]/column[@id="{}"]'.format(attribute)
        try:
            return fixture.findall(xpath)[0].text
        except:
            raise IndicatorError("{} not found in fixture {} for user {}".format(
                attribute, fixture, self.user.get_id
            ))

    def get_messages(self, language_code=None):
        visit_on_time = self.get_value_from_fixture(self.visits_fixture, 'visit_on_time')
        visits = self.get_value_from_fixture(self.visits_fixture, 'count')
        thr_gte_21 = self.get_value_from_fixture(self.thr_fixture, 'open_ccs_thr_gte_21')
        thr_count = self.get_value_from_fixture(self.thr_fixture, 'open_count')
        num_weigh = self.get_value_from_fixture(self.weighed_fixture, 'open_weighed')
        num_weigh_avail = self.get_value_from_fixture(self.weighed_fixture, 'open_count')
        num_days_open = int(self.get_value_from_fixture(self.days_open_fixture, 'awc_opened_count'))
        num_awc_locations = len(self.days_open_fixture.findall('./rows/row[@is_total_row="False"]'))
        if num_awc_locations:
            avg_days_open = int(round(1.0 * num_days_open / num_awc_locations))
        else:
            # catch div by 0
            avg_days_open = 0

        context = {
            "visits": "{} / {}".format(visit_on_time, visits),
            "thr_distribution": "{} / {}".format(thr_gte_21, thr_count),
            "children_weighed": "{} / {}".format(num_weigh, num_weigh_avail),
            "days_open": "{}".format(avg_days_open),
        }

        return [self.render_template(context, language_code=language_code)]
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import requests
import time
import subprocess
import os
import sys
#import mailchecker

requests.packages.urllib3.disable_warnings() # Подавление InsecureRequestWarning, с которым я пока ещё не разобрался

# Ключ авторизации Вашего бота Вы можете получить в любом клиенте Telegram у бота @BotFather
# ADMIN_ID - идентификатор пользователя (то есть Вас), которому подчиняется бот
# Чтобы определить Ваш ID, я предлагаю отправить боту сообщение от своего имени (аккаунта) через любой клиент
# А затем получить это сообщения с помощью обычного GET запроса
# Для этого вставьте в адресную строку Вашего браузера следующий адрес, заменив <token> на свой ключ:
# https://api.telegram.org/bot<token>/getUpdates
# Затем, в ответе найдите объект "from":{"id":01234567,"first_name":"Name","username":"username"}
# Внимательно проверьте имя, логин и текст сообщения
# Если всё совпадает, то цифровое значение ключа "id" - это и есть ваш идентификатор

TOKEN = os.environ.get('BOT_TOKEN') # Ключ авторизации для Вашего бота
ADMIN_ID = os.environ.get('BOT_ADMIN_ID') # ID пользователя. Комманды от других пользователей выполняться не будут
try:
    ADMIN_ID = int(ADMIN_ID)
except:
    pass

INTERVAL = 3 # Интервал проверки наличия новых сообщений (обновлений) на сервере в секундах
URL = 'https://api.telegram.org/bot' # Адрес HTTP Bot API
offset = 0 # ID последнего полученного обновления

def check_updates():
    """Проверка обновлений на сервере и инициация действий, в зависимости от команды"""
    global offset
    data = {'offset': offset + 1, 'limit': 5, 'timeout': 0} # Формируем параметры запроса

    try:
        request = requests.post(URL + TOKEN + '/getUpdates', data=data) # Отправка запроса обновлений
    except:
        log_event('Error getting updates') # Логгируем ошибку
        return False # Завершаем проверку

    if not request.status_code == 200: return False # Проверка ответа сервера
    if not request.json()['ok']: return False # Проверка успешности обращения к API
    for update in request.json()['result']: # Проверка каждого элемента списка
        offset = update['update_id'] # Извлечение ID сообщения

        # Ниже, если в обновлении отсутствует блок 'message'
        # или же в блоке 'message' отсутствует блок 'text', тогда
        if not 'message' in update or not 'text' in update['message']:
            log_event('Unknown update: %s' % update) # сохраняем в лог пришедшее обновление
            continue # и переходим к следующему обновлению
        from_id = update['message']['chat']['id'] # Извлечение ID чата (отправителя)
        name = update['message']['chat']['username'] # Извлечение username отправителя
        if from_id <> ADMIN_ID: # Если отправитель не является администратором, то
            send_text("You're not autorized to use me!", from_id) # ему отправляется соответствующее уведомление
            log_event('Unautorized: %s' % update) # обновление записывается в лог
            continue # и цикл переходит к следующему обновлению
        message = update['message']['text'] # Извлечение текста сообщения
        parameters = (offset, name, from_id, message)
        log_event('Message (id%s) from %s (id%s): "%s"' % parameters) # Вывод в лог ID и текста сообщения

        # В зависимости от сообщения, выполняем необходимое действие
        run_command(*parameters)

def run_command(offset, name, from_id, cmd):
    if cmd == '/ping': # Ответ на ping
        send_text(from_id, 'pong') # Отправка ответа

    elif cmd == '/help': # Ответ на help
        send_text(from_id, 'No help today. Sorry.') # Ответ
    elif cmd.startswith('/ttl'):
        say_ttl(cmd)
    elif cmd == '/photo': # Запрос фотографии с подключенной Web-камеры
        # Для оператора If ниже. Если первая попытка успешна - выполняется условие, если нет, то вторая попытка и условие
        # Если и вторая не успешна, тогда отчитываемся об ошибке
        # Всё потому, что на моей конфигурации крайне изредка камера бывает недоступна с первого раза
        if make_photo(offset) or make_photo(offset):
            # Ниже, отправка пользователю уведомления об активности бота
            requests.post(URL + TOKEN + '/sendChatAction', data={'chat_id': from_id, 'action': 'upload_photo'})
            send_photo(from_id, offset) # Вызов процедуры отправки фото
        else:
            send_text(from_id, 'Error occured') # Ответ, сообщающий об ошибке

    elif cmd == '/mail':
        check_mail() # Вызов процедуры проверки почты
    else:
        send_text(from_id, 'Got it.') # Отправка ответа

def log_event(text):
    """
    Процедура логгирования
    ToDo: 1) Запись лога в файл
    """
    event = '%s >> %s' % (time.ctime(), text)
    print event

def send_text(chat_id, text):
    """Отправка текстового сообщения по chat_id
    ToDo: повторная отправка при неудаче"""
    log_event('Sending to %s: %s' % (chat_id, text)) # Запись события в лог
    data = {'chat_id': chat_id, 'text': text} # Формирование запроса
    request = requests.post(URL + TOKEN + '/sendMessage', data=data) # HTTP запрос
    if not request.status_code == 200: # Проверка ответа сервера
        return False # Возврат с неудачей
    return request.json()['ok'] # Проверка успешности обращения к API

def make_photo(photo_id):
    """Обращение к приложению fswebcam для получения снимка с Web-камеры"""
    photo_name = '/tmp/telegram_bot_photo_%s.jpg' % photo_id # Формирование имени файла фотографии
    subprocess.call('fswebcam -q -r 1280x720 %s' % photo_name, shell=True) # Вызов shell-команды
    return os.path.exists(photo_name) # Проверка, появился ли файл с таким названием

def say_ttl(text):
    """Say text using festival ttl module"""
    subprocess.call('festival --tts --language russian', shell=True, stdin=StringIO(text)) # Вызов shell-команды

def send_photo(chat_id, photo_id):
    """Отправка фото по его идентификатору выбранному контакту"""
    data = {'chat_id': chat_id} # Формирование параметров запроса
    photo_name = '/tmp/telegram_bot_photo_%s.jpg' % photo_id # Формирования имени файла фотографии
    if not os.path.exists(photo_name): return False # Проверка существования фотографии
    files = {'photo': open(photo_name, 'rb')} # Открытие фото и присвоение
    request = requests.post(URL + TOKEN + '/sendPhoto', data=data, files=files) # Отправка фото
    return request.json()['ok'] # Возврат True или False, полученного из ответа сервера, в зависимости от результата

def check_mail():
    """Проверка почтовых ящиков с помощью самодельного модуля"""
    print "Подключите и настройте модуль проверки почты"
    return False
    try:
        log_event('Checking mail...') # Запись в лог
        respond = mailchecker.check_all() # Получаем ответ от модуля проверки
    except:
        log_event('Mail check failed.') # Запись в лог
        return False # И возврат с неудачей
    if not respond: respond = 'No new mail.' # Если ответ пустой, тогда заменяем его на соответствующее сообщение
    send_text(ADMIN_ID, respond) # Отправляем это сообщение администратору
    return True

if __name__ == "__main__":
    if not TOKEN or not ADMIN_ID:
        print("You should provide BOT_TOKEN and BOT_ADMIN_ID")
	sys.exit(1)
    while True:
        try:
            check_updates()
            time.sleep(INTERVAL)
        except KeyboardInterrupt:
            print 'Прервано пользователем..'
            break
<commit_msg>Update say command<commit_after># -*- coding: utf-8 -*-
import requests
import time
import subprocess
import os
import sys
#import mailchecker

requests.packages.urllib3.disable_warnings() # Подавление InsecureRequestWarning, с которым я пока ещё не разобрался

# Ключ авторизации Вашего бота Вы можете получить в любом клиенте Telegram у бота @BotFather
# ADMIN_ID - идентификатор пользователя (то есть Вас), которому подчиняется бот
# Чтобы определить Ваш ID, я предлагаю отправить боту сообщение от своего имени (аккаунта) через любой клиент
# А затем получить это сообщения с помощью обычного GET запроса
# Для этого вставьте в адресную строку Вашего браузера следующий адрес, заменив <token> на свой ключ:
# https://api.telegram.org/bot<token>/getUpdates
# Затем, в ответе найдите объект "from":{"id":01234567,"first_name":"Name","username":"username"}
# Внимательно проверьте имя, логин и текст сообщения
# Если всё совпадает, то цифровое значение ключа "id" - это и есть ваш идентификатор

TOKEN = os.environ.get('BOT_TOKEN') # Ключ авторизации для Вашего бота
ADMIN_ID = os.environ.get('BOT_ADMIN_ID') # ID пользователя. Комманды от других пользователей выполняться не будут
try:
    ADMIN_ID = int(ADMIN_ID)
except:
    pass

INTERVAL = 3 # Интервал проверки наличия новых сообщений (обновлений) на сервере в секундах
URL = 'https://api.telegram.org/bot' # Адрес HTTP Bot API
offset = 0 # ID последнего полученного обновления

def check_updates():
    """Проверка обновлений на сервере и инициация действий, в зависимости от команды"""
    global offset
    data = {'offset': offset + 1, 'limit': 5, 'timeout': 0} # Формируем параметры запроса

    try:
        request = requests.post(URL + TOKEN + '/getUpdates', data=data) # Отправка запроса обновлений
    except:
        log_event('Error getting updates') # Логгируем ошибку
        return False # Завершаем проверку

    if not request.status_code == 200: return False # Проверка ответа сервера
    if not request.json()['ok']: return False # Проверка успешности обращения к API
    for update in request.json()['result']: # Проверка каждого элемента списка
        offset = update['update_id'] # Извлечение ID сообщения

        # Ниже, если в обновлении отсутствует блок 'message'
        # или же в блоке 'message' отсутствует блок 'text', тогда
        if not 'message' in update or not 'text' in update['message']:
            log_event('Unknown update: %s' % update) # сохраняем в лог пришедшее обновление
            continue # и переходим к следующему обновлению
        from_id = update['message']['chat']['id'] # Извлечение ID чата (отправителя)
        name = update['message']['chat']['username'] # Извлечение username отправителя
        if from_id <> ADMIN_ID: # Если отправитель не является администратором, то
            send_text("You're not autorized to use me!", from_id) # ему отправляется соответствующее уведомление
            log_event('Unautorized: %s' % update) # обновление записывается в лог
            continue # и цикл переходит к следующему обновлению
        message = update['message']['text'] # Извлечение текста сообщения
        parameters = (offset, name, from_id, message)
        log_event('Message (id%s) from %s (id%s): "%s"' % parameters) # Вывод в лог ID и текста сообщения

        # В зависимости от сообщения, выполняем необходимое действие
        run_command(*parameters)

def run_command(offset, name, from_id, cmd):
    if cmd == '/ping': # Ответ на ping
        send_text(from_id, 'pong') # Отправка ответа

    elif cmd == '/help': # Ответ на help
        send_text(from_id, 'No help today. Sorry.') # Ответ
    elif cmd.startswith('/ttl'):
        say_ttl(cmd[5:])
    elif cmd == '/photo': # Запрос фотографии с подключенной Web-камеры
        # Для оператора If ниже. Если первая попытка успешна - выполняется условие, если нет, то вторая попытка и условие
        # Если и вторая не успешна, тогда отчитываемся об ошибке
        # Всё потому, что на моей конфигурации крайне изредка камера бывает недоступна с первого раза
        if make_photo(offset) or make_photo(offset):
            # Ниже, отправка пользователю уведомления об активности бота
            requests.post(URL + TOKEN + '/sendChatAction', data={'chat_id': from_id, 'action': 'upload_photo'})
            send_photo(from_id, offset) # Вызов процедуры отправки фото
        else:
            send_text(from_id, 'Error occured') # Ответ, сообщающий об ошибке

    elif cmd == '/mail':
        check_mail() # Вызов процедуры проверки почты
    else:
        send_text(from_id, 'Got it.') # Отправка ответа

def log_event(text):
    """
    Процедура логгирования
    ToDo: 1) Запись лога в файл
    """
    event = '%s >> %s' % (time.ctime(), text)
    print event

def send_text(chat_id, text):
    """Отправка текстового сообщения по chat_id
    ToDo: повторная отправка при неудаче"""
    log_event('Sending to %s: %s' % (chat_id, text)) # Запись события в лог
    data = {'chat_id': chat_id, 'text': text} # Формирование запроса
    request = requests.post(URL + TOKEN + '/sendMessage', data=data) # HTTP запрос
    if not request.status_code == 200: # Проверка ответа сервера
        return False # Возврат с неудачей
    return request.json()['ok'] # Проверка успешности обращения к API

def make_photo(photo_id):
    """Обращение к приложению fswebcam для получения снимка с Web-камеры"""
    photo_name = '/tmp/telegram_bot_photo_%s.jpg' % photo_id # Формирование имени файла фотографии
    subprocess.call('fswebcam -q -r 1280x720 %s' % photo_name, shell=True) # Вызов shell-команды
    return os.path.exists(photo_name) # Проверка, появился ли файл с таким названием

def say_ttl(text):
    """Say text using festival ttl module"""
    subprocess.Popen(["festival", "--tts", "--language", "russian"], stdin=subprocess.PIPE).communicate(text.encode('utf8')) # Вызов shell-команды

def send_photo(chat_id, photo_id):
    """Отправка фото по его идентификатору выбранному контакту"""
    data = {'chat_id': chat_id} # Формирование параметров запроса
    photo_name = '/tmp/telegram_bot_photo_%s.jpg' % photo_id # Формирования имени файла фотографии
    if not os.path.exists(photo_name): return False # Проверка существования фотографии
    files = {'photo': open(photo_name, 'rb')} # Открытие фото и присвоение
    request = requests.post(URL + TOKEN + '/sendPhoto', data=data, files=files) # Отправка фото
    return request.json()['ok'] # Возврат True или False, полученного из ответа сервера, в зависимости от результата

def check_mail():
    """Проверка почтовых ящиков с помощью самодельного модуля"""
    print "Подключите и настройте модуль проверки почты"
    return False
    try:
        log_event('Checking mail...') # Запись в лог
        respond = mailchecker.check_all() # Получаем ответ от модуля проверки
    except:
        log_event('Mail check failed.') # Запись в лог
        return False # И возврат с неудачей
    if not respond: respond = 'No new mail.' # Если ответ пустой, тогда заменяем его на соответствующее сообщение
    send_text(ADMIN_ID, respond) # Отправляем это сообщение администратору
    return True

if __name__ == "__main__":
    if not TOKEN or not ADMIN_ID:
        print("You should provide BOT_TOKEN and BOT_ADMIN_ID")
	sys.exit(1)
    while True:
        try:
            check_updates()
            time.sleep(INTERVAL)
        except KeyboardInterrupt:
            print 'Прервано пользователем..'
            break
<|endoftext|>


<commit_before>"""
kombu.transport.beanstalk
=========================

Beanstalk transport.

:copyright: (c) 2010 - 2013 by David Ziegler.
:license: BSD, see LICENSE for more details.

"""
from __future__ import absolute_import

import beanstalkc
import socket

from anyjson import loads, dumps

from kombu.five import Empty
from kombu.utils.encoding import bytes_to_str

from . import virtual

DEFAULT_PORT = 11300

__author__ = 'David Ziegler <david.ziegler@gmail.com>'

class Channel(virtual.Channel):
    _client = None

    def _parse_job(self, job):
        item, dest = None, None
        if job:
            try:
                item = loads(bytes_to_str(job.body))
                dest = job.stats()['tube']
            except Exception:
                job.bury()
            else:
                job.delete()
        else:
            raise Empty()
        return item, dest

    def _put(self, queue, message, **kwargs):
        extra = {}
        priority = message['properties']['delivery_info']['priority']
        ttr = message['properties'].get('ttr')
        if ttr is not None:
            extra['ttr'] = ttr

        self.client.use(queue)
        self.client.put(dumps(message), priority=priority, **extra)

    def _get(self, queue):
        if queue not in self.client.watching():
            self.client.watch(queue)

        [self.client.ignore(active) for active in self.client.watching()
         if active != queue]

        job = self.client.reserve(timeout=1)
        item, dest = self._parse_job(job)
        return item

    def _get_many(self, queues, timeout=1):
        # timeout of None will cause beanstalk to timeout waiting
        # for a new request
        if timeout is None:
            timeout = 1

        watching = self.client.watching()

        [self.client.watch(active) for active in queues
         if active not in watching]

        [self.client.ignore(active) for active in watching
         if active not in queues]

        job = self.client.reserve(timeout=timeout)
        return self._parse_job(job)

    def _purge(self, queue):
        if queue not in self.client.watching():
            self.client.watch(queue)

        [self.client.ignore(active)
         for active in self.client.watching()
         if active != queue]
        count = 0
        while 1:
            job = self.client.reserve(timeout=1)
            if job:
                job.delete()
                count += 1
            else:
                break
        return count

    def _size(self, queue):
        return 0

    def _open(self):
        conninfo = self.connection.client
        host = conninfo.hostname or 'localhost'
        port = conninfo.port or DEFAULT_PORT
        conn = beanstalkc.Connection(host=host, port=port)
        conn.connect()
        return conn

    def close(self):
        if self._client is not None:
            return self._client.close()
        super(Channel, self).close()

    @property
    def client(self):
        if self._client is None:
            self._client = self._open()
        return self._client

class Transport(virtual.Transport):
    Channel = Channel

    polling_interval = 1
    default_port = DEFAULT_PORT
    connection_errors = (
        virtual.Transport.connection_errors + (
            socket.error, beanstalkc.SocketError, IOError)
    )
    channel_errors = (
        virtual.Transport.channel_errors + (
            socket.error, IOError,
            beanstalkc.SocketError,
            beanstalkc.BeanstalkcException)
    )
    driver_type = 'beanstalk'
    driver_name = 'beanstalkc'

    def driver_version(self):
        return beanstalkc.__version__
<commit_msg>beanstalk can now be imported without beanstalkc dependency<commit_after>"""
kombu.transport.beanstalk
=========================

Beanstalk transport.

:copyright: (c) 2010 - 2013 by David Ziegler.
:license: BSD, see LICENSE for more details.

"""
from __future__ import absolute_import

import socket

from anyjson import loads, dumps

from kombu.five import Empty
from kombu.utils.encoding import bytes_to_str

from . import virtual

try:
    import beanstalkc
except ImportError:  # pragma: no cover
    beanstalkc = None  # noqa

DEFAULT_PORT = 11300

__author__ = 'David Ziegler <david.ziegler@gmail.com>'

class Channel(virtual.Channel):
    _client = None

    def _parse_job(self, job):
        item, dest = None, None
        if job:
            try:
                item = loads(bytes_to_str(job.body))
                dest = job.stats()['tube']
            except Exception:
                job.bury()
            else:
                job.delete()
        else:
            raise Empty()
        return item, dest

    def _put(self, queue, message, **kwargs):
        extra = {}
        priority = message['properties']['delivery_info']['priority']
        ttr = message['properties'].get('ttr')
        if ttr is not None:
            extra['ttr'] = ttr

        self.client.use(queue)
        self.client.put(dumps(message), priority=priority, **extra)

    def _get(self, queue):
        if queue not in self.client.watching():
            self.client.watch(queue)

        [self.client.ignore(active) for active in self.client.watching()
         if active != queue]

        job = self.client.reserve(timeout=1)
        item, dest = self._parse_job(job)
        return item

    def _get_many(self, queues, timeout=1):
        # timeout of None will cause beanstalk to timeout waiting
        # for a new request
        if timeout is None:
            timeout = 1

        watching = self.client.watching()

        [self.client.watch(active) for active in queues
         if active not in watching]

        [self.client.ignore(active) for active in watching
         if active not in queues]

        job = self.client.reserve(timeout=timeout)
        return self._parse_job(job)

    def _purge(self, queue):
        if queue not in self.client.watching():
            self.client.watch(queue)

        [self.client.ignore(active)
         for active in self.client.watching()
         if active != queue]
        count = 0
        while 1:
            job = self.client.reserve(timeout=1)
            if job:
                job.delete()
                count += 1
            else:
                break
        return count

    def _size(self, queue):
        return 0

    def _open(self):
        conninfo = self.connection.client
        host = conninfo.hostname or 'localhost'
        port = conninfo.port or DEFAULT_PORT
        conn = beanstalkc.Connection(host=host, port=port)
        conn.connect()
        return conn

    def close(self):
        if self._client is not None:
            return self._client.close()
        super(Channel, self).close()

    @property
    def client(self):
        if self._client is None:
            self._client = self._open()
        return self._client

class Transport(virtual.Transport):
    Channel = Channel

    polling_interval = 1
    default_port = DEFAULT_PORT
    connection_errors = (
        virtual.Transport.connection_errors + (
            socket.error, IOError,
            getattr(beanstalkc, 'SocketError', None),
        )
    )
    channel_errors = (
        virtual.Transport.channel_errors + (
            socket.error, IOError,
            getattr(beanstalkc, 'SocketError', None),
            getattr(beanstalkc, 'BeanstalkcException', None),
        )
    )
    driver_type = 'beanstalk'
    driver_name = 'beanstalkc'

    def __init__(self, *args, **kwargs):
        if beanstalkc is None:
            raise ImportError(
                'Missing beanstalkc library (pip install beanstalkc)')
        super(Transport, self).__init__(*args, **kwargs)

    def driver_version(self):
        return beanstalkc.__version__
<|endoftext|>


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

# Weckan -- Web application using CKAN model
# By: Axel Haustant <axel@haustant.fr>
#
# Copyright (C) 2013 Axel Haustant
# http://github.com/etalab/weckan
#
# This file is part of Weckan.
#
# Weckan is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Weckan is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals

import json
import urllib
import urlparse

from os.path import join, dirname, abspath
from pkg_resources import resource_stream

from jinja2 import Environment, PackageLoader
from jinja2.utils import Markup
from webassets import Environment as AssetsEnvironment
from webassets.ext.jinja2 import AssetsExtension
from webassets.loaders import YAMLLoader

from babel import dates

from .. import conf, contexts, auth

env = None

# Langugages definitions: language code => (Display name, flag)
LANGUAGES = {
    'fr': u'Français',
    'en': u'English',
    'de': u'Deutsch',
}
DEFAULT_LANG = 'fr'

DEFAULT_STATIC = abspath(join(dirname(__file__), '..', 'static'))

GRAVATAR_DEFAULTS = ('404', 'mm', 'identicon', 'monsterid', 'wavatar', 'retro')

GROUPS = (
    (u'Culture et communication', 'culture', None),
    (u'Développement durable', 'wind', '{wiki}/Le_D%C3%A9veloppement_Durable'),
    (u'Éducation et recherche', 'education', None),
    (u'Justice', 'justice', None),
    (u'Santé et solidarité', 'heart', None),
    (u'Sécurité et défense', 'shield', None),
    (u'Société', 'people', None),
    (u'Travail, économie, emploi', 'case', None),
)

MAIN_TOPICS = None

def format_group_url(row):
    url = row[2].format(
        home=conf['home_url'], wiki=conf['wiki_url'], questions=conf['questions_url']
    ) if row[2] else None
    return (row[0], row[1], url)

def url(*args, **kwargs):
    '''Get an URL from parts'''
    from .. import urls
    return urls.get_url(None, *args, **kwargs)

def static(*args, **kwargs):
    '''Get a static asset path'''
    return url(*args, **kwargs)

def format_datetime(value, format='short', locale='fr'):
    '''Format a datetime given a locale'''
    try:
        return dates.format_datetime(value, format, locale=locale)
    except:
        return value

def format_date(value, format='display', locale='fr'):
    '''Format a date given a locale'''
    if format == 'display':
        _ = contexts.Ctx().translator.gettext
        # TRANSLATORS: Short date format with full year (4-digits)
        format = _('MM-dd-yyyy')
    try:
        return dates.format_date(value, format, locale=locale)
    except:
        return value

def avatar(user, size=100):
    url = '{0}/u/{1}/avatar'.format(conf['sso_url'], user.name)
    return ''.format(url, size)

def swig(value):
    '''Transform a string into a swig variable'''
    return ''.join(['{{', value, '}}'])

def user_by_id(user_id):
    '''Get a user from its id'''
    from weckan.model import User
    return User.get(user_id)

def tooltip_ellipsis(source, length=0):
    ''' return the plain text representation of markdown encoded text.  That
    is the texted without any html tags.  If ``length`` is 0 then it
    will not be truncated.'''
    try:
        length = int(length)
    except ValueError:  # invalid literal for int()
        return source  # Fail silently.
    ellipsis = '...'.format(source)
    return (source[:length] + ellipsis) if len(source) > length and length > 0 else source

def get_webassets_env(conf):
    '''Get a preconfigured WebAssets environment'''
    # Configure webassets
    assets_environment = AssetsEnvironment(conf.get('static_files_dir', DEFAULT_STATIC), '/')
    assets_environment.debug = conf.get('debug', False)
    assets_environment.auto_build = conf.get('debug', False)
    assets_environment.config['less_paths'] = ('bower/bootstrap/less', 'bower/etalab-assets/less')

    # Load bundle from yaml file
    loader = YAMLLoader(resource_stream(__name__, '../assets.yaml'))
    bundles = loader.load_bundles()
    for name, bundle in bundles.items():
        assets_environment.register(name, bundle)

    return assets_environment

def get_jinja_env():
    '''
    Get a preconfigured jinja environment including:

     - WebAssets
     - i18n
     - global functions
     - filters
    '''
    global env

    if not env:
        from biryani1 import strings
        from ckan.lib.helpers import markdown, markdown_extract
        from weckan.urls import sso_url

        # Configure Jinja Environment with webassets
        env = Environment(
            loader = PackageLoader('weckan', 'templates'),
            extensions = (AssetsExtension, 'jinja2.ext.i18n', 'jinja2.ext.autoescape')
            )
        env.assets_environment = get_webassets_env(conf)

        # Custom global functions
        env.globals['url'] = url
        env.globals['sso'] = sso_url
        env.globals['static'] = static
        env.globals['slugify'] = strings.slugify
        env.globals['ifelse'] = lambda condition, first, second: first if condition else second
        env.globals['avatar'] = avatar
        env.globals['markdown'] = markdown
        env.globals['markdown_extract'] = markdown_extract
        env.globals['user_by_id'] = user_by_id

        # Custom filters
        env.filters['datetime'] = format_datetime
        env.filters['date'] = format_date
        env.filters['swig'] = swig
        env.filters['tooltip_ellipsis'] = tooltip_ellipsis

    return env

def format_topic(topic):
    url = topic['url'].format(
        group='{0}/{{lang}}/groups'.format(conf['home_url']),
        wiki=conf['wiki_url']
    )
    return {'title': topic['title'], 'url': url}

def main_topics():
    global MAIN_TOPICS
    if not MAIN_TOPICS:
        static_root = conf.get('static_files_dir', DEFAULT_STATIC)
        topics_file = join(static_root, 'bower', 'etalab-assets', 'data', 'main_topics.json')
        with open(topics_file) as f:
            MAIN_TOPICS = map(format_topic, json.load(f))
    return MAIN_TOPICS

def render(context, name, **kwargs):
    '''Render a localized template using Jinja'''
    env = get_jinja_env()
    env.install_gettext_translations(context.translator)
    template = env.get_template(name)
    lang = kwargs.pop('lang', DEFAULT_LANG)
    return template.render(lang=lang, languages=LANGUAGES, **kwargs)

def render_site(name, request_or_context, **kwargs):
    '''
    Render a template with a common site behavior.

    - handle language choice and fallback
    - inject user
    - inject sidebar items
    '''
    context = request_or_context if isinstance(request_or_context, contexts.Ctx) else contexts.Ctx(request_or_context)
    lang = context.req.urlvars.get('lang', None)

    # Locale-less location
    current_location = context.req.path_qs
    base_location = current_location.replace('/{0}'.format(lang), '')

    # Override browser language
    if lang in LANGUAGES:
        context.lang = lang
    elif lang is None:
        lang = DEFAULT_LANG
    else:
        from weckan import wsgihelpers
        return wsgihelpers.redirect(context, location=base_location)

    return render(context, name,
        full_url = context.req.url,
        current_location = current_location,
        current_base_location = base_location,
        query_string = context.req.query_string,
        user = auth.get_user_from_request(context.req),
        lang = lang,
        main_topics = main_topics(),
        DOMAIN = conf['domain'],
        HOME_URL = conf['home_url'],
        WIKI_URL = conf['wiki_url'],
        WIKI_API_URL = conf['wiki_api_url'],
        QUESTIONS_URL = conf['questions_url'],
        CKAN_URL = conf['ckan_url'],
        COW_URL = conf['cow_url'],
        SSO_URL = conf['sso_url'],
        **kwargs
    )
<commit_msg>Some escaping fixes<commit_after># -*- coding: utf-8 -*-

# Weckan -- Web application using CKAN model
# By: Axel Haustant <axel@haustant.fr>
#
# Copyright (C) 2013 Axel Haustant
# http://github.com/etalab/weckan
#
# This file is part of Weckan.
#
# Weckan is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Weckan is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals

import json

from os.path import join, dirname, abspath
from pkg_resources import resource_stream

from jinja2 import Environment, PackageLoader
from jinja2.utils import Markup
from webassets import Environment as AssetsEnvironment
from webassets.ext.jinja2 import AssetsExtension
from webassets.loaders import YAMLLoader

from babel import dates

from .. import conf, contexts, auth

env = None

# Langugages definitions: language code => (Display name, flag)
LANGUAGES = {
    'fr': u'Français',
    'en': u'English',
    'de': u'Deutsch',
}
DEFAULT_LANG = 'fr'

DEFAULT_STATIC = abspath(join(dirname(__file__), '..', 'static'))

GRAVATAR_DEFAULTS = ('404', 'mm', 'identicon', 'monsterid', 'wavatar', 'retro')

GROUPS = (
    (u'Culture et communication', 'culture', None),
    (u'Développement durable', 'wind', '{wiki}/Le_D%C3%A9veloppement_Durable'),
    (u'Éducation et recherche', 'education', None),
    (u'Justice', 'justice', None),
    (u'Santé et solidarité', 'heart', None),
    (u'Sécurité et défense', 'shield', None),
    (u'Société', 'people', None),
    (u'Travail, économie, emploi', 'case', None),
)

MAIN_TOPICS = None

def format_group_url(row):
    url = row[2].format(
        home=conf['home_url'], wiki=conf['wiki_url'], questions=conf['questions_url']
    ) if row[2] else None
    return (row[0], row[1], url)

def url(*args, **kwargs):
    '''Get an URL from parts'''
    from .. import urls
    return urls.get_url(None, *args, **kwargs)

def static(*args, **kwargs):
    '''Get a static asset path'''
    return url(*args, **kwargs)

def format_datetime(value, format='short', locale='fr'):
    '''Format a datetime given a locale'''
    try:
        return dates.format_datetime(value, format, locale=locale)
    except:
        return value

def format_date(value, format='display', locale='fr'):
    '''Format a date given a locale'''
    if format == 'display':
        _ = contexts.Ctx().translator.gettext
        # TRANSLATORS: Short date format with full year (4-digits)
        format = _('MM-dd-yyyy')
    try:
        return dates.format_date(value, format, locale=locale)
    except:
        return value

def avatar(user, size=100):
    url = '{0}/u/{1}/avatar'.format(conf['sso_url'], user.name)
    return Markup(''.format(url, size))

def swig(value):
    '''Transform a string into a swig variable'''
    return ''.join(['{{', value, '}}'])

def user_by_id(user_id):
    '''Get a user from its id'''
    from weckan.model import User
    return User.get(user_id)

def tooltip_ellipsis(source, length=0):
    ''' return the plain text representation of markdown encoded text.  That
    is the texted without any html tags.  If ``length`` is 0 then it
    will not be truncated.'''
    try:
        length = int(length)
    except ValueError:  # invalid literal for int()
        return source  # Fail silently.
    ellipsis = '...'.format(source)
    return Markup((source[:length] + ellipsis) if len(source) > length and length > 0 else source)

def markdown_filter(source):
    from ckan.lib.helpers import markdown
    return Markup(markdown(source))

def get_webassets_env(conf):
    '''Get a preconfigured WebAssets environment'''
    # Configure webassets
    assets_environment = AssetsEnvironment(conf.get('static_files_dir', DEFAULT_STATIC), '/')
    assets_environment.debug = conf.get('debug', False)
    assets_environment.auto_build = conf.get('debug', False)
    assets_environment.config['less_paths'] = ('bower/bootstrap/less', 'bower/etalab-assets/less')

    # Load bundle from yaml file
    loader = YAMLLoader(resource_stream(__name__, '../assets.yaml'))
    bundles = loader.load_bundles()
    for name, bundle in bundles.items():
        assets_environment.register(name, bundle)

    return assets_environment

def get_jinja_env():
    '''
    Get a preconfigured jinja environment including:

     - WebAssets
     - i18n
     - global functions
     - filters
    '''
    global env

    if not env:
        from biryani1 import strings
        from ckan.lib.helpers import markdown_extract
        from weckan.urls import sso_url

        # Configure Jinja Environment with webassets
        env = Environment(
            autoescape=True,
            loader=PackageLoader('weckan', 'templates'),
            extensions=(AssetsExtension, 'jinja2.ext.i18n', 'jinja2.ext.autoescape')
        )
        env.assets_environment = get_webassets_env(conf)

        # Custom global functions
        env.globals['url'] = url
        env.globals['sso'] = sso_url
        env.globals['static'] = static
        env.globals['slugify'] = strings.slugify
        env.globals['ifelse'] = lambda condition, first, second: first if condition else second
        env.globals['avatar'] = avatar
        env.globals['markdown'] = markdown_filter
        env.globals['markdown_extract'] = markdown_extract
        env.globals['user_by_id'] = user_by_id

        # Custom filters
        env.filters['datetime'] = format_datetime
        env.filters['date'] = format_date
        env.filters['swig'] = swig
        env.filters['tooltip_ellipsis'] = tooltip_ellipsis

    return env

def format_topic(topic):
    url = topic['url'].format(
        group='{0}/{{lang}}/groups'.format(conf['home_url']),
        wiki=conf['wiki_url']
    )
    return {'title': topic['title'], 'url': url}

def main_topics():
    global MAIN_TOPICS
    if not MAIN_TOPICS:
        static_root = conf.get('static_files_dir', DEFAULT_STATIC)
        topics_file = join(static_root, 'bower', 'etalab-assets', 'data', 'main_topics.json')
        with open(topics_file) as f:
            MAIN_TOPICS = map(format_topic, json.load(f))
    return MAIN_TOPICS

def render(context, name, **kwargs):
    '''Render a localized template using Jinja'''
    env = get_jinja_env()
    env.install_gettext_translations(context.translator)
    template = env.get_template(name)
    lang = kwargs.pop('lang', DEFAULT_LANG)
    return template.render(lang=lang, languages=LANGUAGES, **kwargs)

def render_site(name, request_or_context, **kwargs):
    '''
    Render a template with a common site behavior.

    - handle language choice and fallback
    - inject user
    - inject sidebar items
    '''
    context = request_or_context if isinstance(request_or_context, contexts.Ctx) else contexts.Ctx(request_or_context)
    lang = context.req.urlvars.get('lang', None)

    # Locale-less location
    current_location = context.req.path_qs
    base_location = current_location.replace('/{0}'.format(lang), '')

    # Override browser language
    if lang in LANGUAGES:
        context.lang = lang
    elif lang is None:
        lang = DEFAULT_LANG
    else:
        from weckan import wsgihelpers
        return wsgihelpers.redirect(context, location=base_location)

    return render(context, name,
        full_url = context.req.url,
        current_location = current_location,
        current_base_location = base_location,
        query_string = context.req.query_string,
        user = auth.get_user_from_request(context.req),
        lang = lang,
        main_topics = main_topics(),
        DOMAIN = conf['domain'],
        HOME_URL = conf['home_url'],
        WIKI_URL = conf['wiki_url'],
        WIKI_API_URL = conf['wiki_api_url'],
        QUESTIONS_URL = conf['questions_url'],
        CKAN_URL = conf['ckan_url'],
        COW_URL = conf['cow_url'],
        SSO_URL = conf['sso_url'],
        **kwargs
    )
<|endoftext|>


<commit_before>import sys
from os.path import expanduser, join, exists, dirname
from pprint import pprint
from fabric.api import task

import default_settings

def import_module(name, package=None):
    __import__(name)
    return sys.modules[name]

class Settings(object):
    """
    Settings object inspired by django.conf.settings.
    """
    def __init__(self):
        self._apply_settings_from_module(default_settings)
        custom_settings = import_module('awsfab_settings')
        self._apply_settings_from_module(custom_settings)

    def _apply_settings_from_module(self, settings_module):
        for setting in dir(settings_module):
            if setting == setting.upper():
                setattr(self, setting, getattr(settings_module, setting))

    def as_dict(self):
        """
        Get all settings (uppercase attributes on this object) as a dict.
        """
        dct = {}
        for attrname, value in self.__dict__.iteritems():
            if attrname.upper() == attrname:
                dct[attrname] = value
        return dct

    def pprint(self):
        """
        Prettyprint the settings.
        """
        pprint(self.as_dict())

    #def get_key_filenames(self, key_name):
        #"""
        #Search for ``<key_name>.pem`` in awsfab_settings.KEYPAIR_PATH, and return a
        #list of all of the files we find.
        #"""
        #filenames = []
        #for dirpath in self.KEYPAIR_PATH:
            #filename = join(expanduser(dirpath), key_name) + '.pem'
            #if exists(filename):
                #filenames.append(filename)
        #return filenames

awsfab_settings = Settings()

@task
def print_settings():
    """
    Pretty-print the settings as they are seen by the system.
    """
    awsfab_settings.pprint()

@task
def print_default_settings():
    """
    Print ``default_settings.py``.
    """
    path = join(dirname(default_settings.__file__), 'default_settings.py')
    print open(path).read()
<commit_msg>conf: Removed get_key_filenames.<commit_after>import sys
from os.path import expanduser, join, exists, dirname
from pprint import pprint
from fabric.api import task

import default_settings

def import_module(name, package=None):
    __import__(name)
    return sys.modules[name]

class Settings(object):
    """
    Settings object inspired by django.conf.settings.
    """
    def __init__(self):
        self._apply_settings_from_module(default_settings)
        custom_settings = import_module('awsfab_settings')
        self._apply_settings_from_module(custom_settings)

    def _apply_settings_from_module(self, settings_module):
        for setting in dir(settings_module):
            if setting == setting.upper():
                setattr(self, setting, getattr(settings_module, setting))

    def as_dict(self):
        """
        Get all settings (uppercase attributes on this object) as a dict.
        """
        dct = {}
        for attrname, value in self.__dict__.iteritems():
            if attrname.upper() == attrname:
                dct[attrname] = value
        return dct

    def pprint(self):
        """
        Prettyprint the settings.
        """
        pprint(self.as_dict())

awsfab_settings = Settings()

@task
def print_settings():
    """
    Pretty-print the settings as they are seen by the system.
    """
    awsfab_settings.pprint()

@task
def print_default_settings():
    """
    Print ``default_settings.py``.
    """
    path = join(dirname(default_settings.__file__), 'default_settings.py')
    print open(path).read()
<|endoftext|>