<commit_before>import sqlalchemy as alc
from sqlalchemy import create_engine, MetaData
from rdrf.dynamic_data import DynamicDataWrapper
import explorer
from explorer.utils import DatabaseUtils

import logging
logger = logging.getLogger("registry_log")

from django.conf import settings

def temporary_table_name(query_model, user):
    return "report_%s_%s" % (query_model.id, user.pk)

class ReportingTableGenerator(object):
    DEMOGRAPHIC_FIELDS = [('family_name', 'todo', alc.String),
                          ('given_names', 'todo', alc.String),
                          ('home_phone', 'todo', alc.String),
                          ('email', 'todo', alc.String)]
    TYPE_MAP = {"float": alc.Float,
                "calculated": alc.String, #todo fix this - some calculated field are strings some numbers
                "integer": alc.Integer,
                "int": alc.Integer,
                "string": alc.String,
                }

    def __init__(self, user, registry_model, multisection_unroller, humaniser, type_overrides={}):
        self.user = user
        self.counter = 0
        self.col_map = {}
        self.registry_model = registry_model
        self.type_overrides = type_overrides
        self.engine = self._create_engine()
        self.columns = set([])
        self.table_name = ""
        self.table = None
        self.reverse_map = {}
        self.multisection_column_map = {}
        self.multisection_unroller = multisection_unroller
        self.humaniser = humaniser

    def _create_engine(self):
        report_db_data = settings.DATABASES["reporting"]
        db_user = report_db_data["USER"]
        db_pass = report_db_data["PASSWORD"]
        database = report_db_data["NAME"]
        host = report_db_data["HOST"]
        port = report_db_data["PORT"]
        connection_string = "postgresql://{0}:{1}@{2}:{3}/{4}".format(db_user,
                                                                      db_pass,
                                                                      host,
                                                                      port,
                                                                      database)

        logger.debug("connection_string = %s" % connection_string)
        return create_engine(connection_string)

    def create_table(self):
        self.table.create()
        logger.debug("created table based on schema")

    def drop_table(self):
        drop_table_sql = "DROP TABLE %s" % self.table_name
        conn = self.engine.connect()
        try:
            conn.execute(drop_table_sql)
            logger.debug("dropped temp table %s" % self.table_name)
        except:
            pass
        conn.close()

    def set_table_name(self, obj):
        logger.debug("setting table name from %s %s" % (self.user.username, obj))
        self.table_name = temporary_table_name(obj, self.user)
        logger.info("table name = %s" % self.table_name)

    def _add_reverse_mapping(self, key, value):
        self.reverse_map[key] = value
        logger.debug("reverse map %s --> %s" % (key, value))

    def create_columns(self, sql_metadata, mongo_metadata):
        logger.debug("creating columns from sql and mongo metadata")
        self.columns = set([])
        self.columns.add(self._create_column("context_id", alc.Integer))
        # These columns will always appear
        self._add_reverse_mapping("context_id", "context_id")

        self.columns.add(self._create_column("timestamp", alc.String))
        self._add_reverse_mapping("timestamp", "timestamp")

        self.columns.add(self._create_column("snapshot", alc.Boolean))
        self._add_reverse_mapping("snapshot", "snapshot")

        for i, column_metadata in enumerate(sql_metadata):
            column_from_sql = self._create_column_from_sql(column_metadata)
            self.columns.add(column_from_sql)
            #to get from tuple
            # map the column's index in tuple to the column name in the dict
            self._add_reverse_mapping(i, column_metadata["name"])

        for form_model, section_model, cde_model in mongo_metadata["multisection_column_map"]:
            column_name = mongo_metadata["multisection_column_map"][(form_model, section_model, cde_model)]
            column_from_mongo = self._create_column_from_mongo(column_name, form_model, section_model, cde_model)
            self.columns.add(column_from_mongo)

    def _create_column_from_sql(self, column_metadata):
        logger.debug("column metadata = %s" % column_metadata)
        column_name = column_metadata["name"]
        type_name = column_metadata["type_name"]
        # Not sure if this good idea ...
        # these type_names are coming from introspection on the sql cursor
        if type_name == "varchar":
            datatype = alc.String
        elif type_name == "bool":
            datatype = alc.Boolean
        elif "float" in type_name:
            datatype = alc.FLOAT
        elif "int" in type_name:
            datatype = alc.INTEGER
        elif "date" in type_name:
            datatype = alc.DATE
        else:
            datatype = alc.String

        logger.debug("mapped sql alc data type = %s" % datatype)
        return self._create_column(column_name, datatype)

    def _create_column_from_mongo(self, column_name, form_model, section_model, cde_model):
        column_data_type = self._get_sql_alchemy_datatype(cde_model)
        logger.debug("**** cde %s datatype %s  --> column datatype %s" % (cde_model.code, cde_model.datatype,
                                                                        column_data_type))
        self._add_reverse_mapping((form_model, section_model, cde_model), column_name)
        if section_model.allow_multiple:
            # This map is used when we unroll/"denormalise" the multisection data
            logger.debug("multisection_column_map = %s" % self.multisection_column_map)
            if section_model.code in self.multisection_column_map:
                self.multisection_column_map[section_model.code].append(column_name)
            else:
                self.multisection_column_map[section_model.code] = [column_name]

        return self._create_column(column_name, column_data_type)

    def run_explorer_query(self, database_utils):
        self.create_table()
        self.multisection_unroller.multisection_column_map = self.multisection_column_map
        errors = 0
        for result_dict in database_utils.generate_results(self.reverse_map):
            for unrolled_row in self.multisection_unroller.unroll(result_dict):
                try:
                    self.insert_row(unrolled_row)
                except Exception, ex:
                    errors += 1
                    logger.error("report error: query %s row %s error: %s" % (database_utils.form_object.title,
                                                                              unrolled_row,
                                                                              ex))
        logger.info("query errors: %s" % errors)

    def insert_row(self, value_dict):
        # each row will be a denormalised section item
        logger.debug("inserting context dict: %s" % value_dict)
        self.engine.execute(self.table.insert().values(**value_dict))

    def _create_column(self, name, datatype=alc.String):
        column = alc.Column(name, datatype, nullable=True)
        self.columns.add(column)
        logger.debug("added column %s type %s" % (name, datatype))
        return column

    def create_schema(self):
        self.drop_table()
        logger.debug("creating table schema")
        logger.debug("There are %s columns" % len(self.columns))
        logger.debug("table name will be = %s" % self.table_name)
        self.table = alc.Table(self.table_name, MetaData(self.engine), *self.columns, schema=None)

    def _generate_temporary_table_name(self):
        return "reporting_table" + self.user.username

    def _get_sql_alchemy_datatype(self, cde_model):
        if cde_model.code in self.type_overrides:
            datatype = self.type_overrides[cde_model.code]
        else:
            datatype = cde_model.datatype

        return self.TYPE_MAP.get(datatype, alc.String)

    def dump_csv(self, stream):
        import csv
        writer = csv.writer(stream)
        select_query = alc.sql.select([self.table])
        db_connection = self.engine.connect()
        result = db_connection.execute(select_query)
        writer.writerow(result.keys())
        writer.writerows(result)
        db_connection.close()
        return stream

class MongoFieldSelector(object):
    def __init__(self, user, registry_model, query_model, checkbox_ids=[]):
        if checkbox_ids is not None:
            self.checkbox_ids = checkbox_ids
        else:
            self.checkbox_ids = []

        self.user = user
        self.registry_model = registry_model
        self.query_model = query_model
        if self.query_model:
            self.existing_data = self._get_existing_report_choices(self.query_model)
        else:
            self.existing_data = {}

    def _get_existing_report_choices(self, query_model):
        import json
        try:
            return json.loads(query_model.projection)
        except:
            return []

    @property
    def field_data(self):
        return {"fields": self.fields}

    @property
    def fields(self):
        self.field_info = []
        for form_model in self.registry_model.forms:
            if self.user.can_view(form_model) and not form_model.is_questionnaire:
                for section_model in form_model.section_models:
                    for cde_model in section_model.cde_models:
                        self._get_field_info(form_model, section_model, cde_model)

        return self.field_info

    def _get_saved_value(self, form_model, section_model, cde_model):
        for value_dict in self.existing_data:
            if value_dict["formName"] == form_model.name:
                if value_dict["sectionCode"] == section_model.code:
                    if value_dict["cdeCode"] == cde_model.code:
                        return value_dict["value"]
        return False

    def _get_field_info(self, form_model, section_model, cde_model):
        saved_value = self._get_saved_value(form_model, section_model, cde_model)
        field_id = "cb_%s_%s_%s_%s" % (self.registry_model.code,
                                       form_model.pk,
                                       section_model.pk,
                                       cde_model.pk)
        field_label = cde_model.name
        self.field_info.append({"form": form_model.name,
                                "sectionCode": section_model.code,
                                "sectionName": section_model.display_name,
                                "cdeCode": cde_model.code,
                                "id": field_id,
                                "label": field_label,
                                "savedValue": saved_value})

    @property
    def projections_json(self):
        # this method returns the new projection data back to the client based
        # on the list of checked items passed in
        # the constructed json is independent of db ids ( as these will change
        # is import of registry definition occurs
        import json
        from rdrf.models import Registry, RegistryForm, Section, CommonDataElement
        projected_cdes = []
        for checkbox_id in self.checkbox_ids:
            # <input type="checkbox" name="cb_fh_39_104_CarotidUltrasonography" id="cb_fh_39_104_CarotidUltrasonography">
            # registry code, form pk, section pk, cde_code
            # cb_fh_39_105_EchocardiogramResult
            _, registry_code, form_pk, section_pk, cde_code = checkbox_id.split("_")

            form_model = RegistryForm.objects.get(pk=int(form_pk))
            section_model = Section.objects.get(pk=int(section_pk))
            cde_model = CommonDataElement.objects.get(code=cde_code)

            value_dict = {}
            value_dict["registryCode"] = form_model.registry.code
            value_dict["formName"] = form_model.name
            value_dict["sectionCode"] = section_model.code
            value_dict["cdeCode"] = cde_model.code
            value_dict["value"] = True  # we only need to store the true / checked cdes

            projected_cdes.append(value_dict)

        logger.debug("projected cdes = %s" % projected_cdes)
        return json.dumps(projected_cdes)

class ReportTable(object):
    """
    Used by report datatable view
    """

    def __init__(self,  user, query_model):
        self.query_model = query_model
        self.user = user
        self.engine = self._create_engine()
        self.table_name = temporary_table_name(self.query_model, self.user)
        self.table = self._get_table()
        self._converters = {
            "date_of_birth": str,
        }

    @property
    def title(self):
        return "Report Table By Lee"

    @property
    def columns(self):
        return [{"data": col.name, "label": col.name} for col in self.table.columns]

    def _get_table(self):
        return alc.Table(self.table_name, MetaData(self.engine), autoload=True, autoload_with=self.engine)

    def _create_engine(self):
        report_db_data = settings.DATABASES["reporting"]
        db_user = report_db_data["USER"]
        db_pass = report_db_data["PASSWORD"]
        database = report_db_data["NAME"]
        host = report_db_data["HOST"]
        port = report_db_data["PORT"]
        connection_string = "postgresql://{0}:{1}@{2}:{3}/{4}".format(db_user,
                                                                      db_pass,
                                                                      host,
                                                                      port,
                                                                      database)
        return create_engine(connection_string)

    def run_query(self, params=None):
        from sqlalchemy.sql import select
        rows = []
        columns = [col for col in self.table.columns]
        query = select([self.table])
        if params is None:
            pass
        else:
            if "sort_field" in params:
                sort_field = params["sort_field"]
                sort_direction = params["sort_direction"]

                sort_column = getattr(self.table.c, sort_field)
                logger.debug("sorting by %s" % sort_column.name)

                if sort_direction == "asc":
                    logger.debug("sort direction is ascending")
                    sort_column = sort_column.asc()
                else:
                    logger.debug("sort direction is descending")
                    sort_column = sort_column.desc()

                query = query.order_by(sort_column)

        for row in self.engine.execute(query):
                result_dict = {}
                for i, col in enumerate(columns):
                    result_dict[col.name] = self._format(col.name, row[i])
                rows.append(result_dict)
        return rows

    def _format(self, column, data):
        converter = self._converters.get(column, None)
        if converter is None:
            return data
        else:
            return converter(data)

<commit_msg>RDR-1143 timing code/removed unnecessary logging<commit_after>import sqlalchemy as alc
from sqlalchemy import create_engine, MetaData
from rdrf.dynamic_data import DynamicDataWrapper
import explorer
from explorer.utils import DatabaseUtils
from rdrf.utils import timed

import logging
logger = logging.getLogger("registry_log")

from django.conf import settings

def temporary_table_name(query_model, user):
    return "report_%s_%s" % (query_model.id, user.pk)

class ReportingTableGenerator(object):
    DEMOGRAPHIC_FIELDS = [('family_name', 'todo', alc.String),
                          ('given_names', 'todo', alc.String),
                          ('home_phone', 'todo', alc.String),
                          ('email', 'todo', alc.String)]
    TYPE_MAP = {"float": alc.Float,
                "calculated": alc.String, #todo fix this - some calculated field are strings some numbers
                "integer": alc.Integer,
                "int": alc.Integer,
                "string": alc.String,
                }

    def __init__(self, user, registry_model, multisection_unroller, humaniser, type_overrides={}):
        self.user = user
        self.counter = 0
        self.col_map = {}
        self.registry_model = registry_model
        self.type_overrides = type_overrides
        self.engine = self._create_engine()
        self.columns = set([])
        self.table_name = ""
        self.table = None
        self.reverse_map = {}
        self.multisection_column_map = {}
        self.multisection_unroller = multisection_unroller
        self.humaniser = humaniser

    def _create_engine(self):
        report_db_data = settings.DATABASES["reporting"]
        db_user = report_db_data["USER"]
        db_pass = report_db_data["PASSWORD"]
        database = report_db_data["NAME"]
        host = report_db_data["HOST"]
        port = report_db_data["PORT"]
        connection_string = "postgresql://{0}:{1}@{2}:{3}/{4}".format(db_user,
                                                                      db_pass,
                                                                      host,
                                                                      port,
                                                                      database)

        logger.debug("connection_string = %s" % connection_string)
        return create_engine(connection_string)

    @timed
    def create_table(self):
        self.table.create()
        logger.debug("created table based on schema")

    @timed
    def drop_table(self):
        drop_table_sql = "DROP TABLE %s" % self.table_name
        conn = self.engine.connect()
        try:
            conn.execute(drop_table_sql)
            logger.debug("dropped temp table %s" % self.table_name)
        except:
            pass
        conn.close()

    def set_table_name(self, obj):
        logger.debug("setting table name from %s %s" % (self.user.username, obj))
        self.table_name = temporary_table_name(obj, self.user)
        logger.info("table name = %s" % self.table_name)

    def _add_reverse_mapping(self, key, value):
        self.reverse_map[key] = value

    @timed
    def create_columns(self, sql_metadata, mongo_metadata):
        logger.debug("creating columns from sql and mongo metadata")
        self.columns = set([])
        self.columns.add(self._create_column("context_id", alc.Integer))
        # These columns will always appear
        self._add_reverse_mapping("context_id", "context_id")

        self.columns.add(self._create_column("timestamp", alc.String))
        self._add_reverse_mapping("timestamp", "timestamp")

        self.columns.add(self._create_column("snapshot", alc.Boolean))
        self._add_reverse_mapping("snapshot", "snapshot")

        for i, column_metadata in enumerate(sql_metadata):
            column_from_sql = self._create_column_from_sql(column_metadata)
            self.columns.add(column_from_sql)
            #to get from tuple
            # map the column's index in tuple to the column name in the dict
            self._add_reverse_mapping(i, column_metadata["name"])

        for form_model, section_model, cde_model in mongo_metadata["multisection_column_map"]:
            column_name = mongo_metadata["multisection_column_map"][(form_model, section_model, cde_model)]
            column_from_mongo = self._create_column_from_mongo(column_name, form_model, section_model, cde_model)
            self.columns.add(column_from_mongo)

    def _create_column_from_sql(self, column_metadata):
        column_name = column_metadata["name"]
        type_name = column_metadata["type_name"]
        # Not sure if this good idea ...
        # these type_names are coming from introspection on the sql cursor
        if type_name == "varchar":
            datatype = alc.String
        elif type_name == "bool":
            datatype = alc.Boolean
        elif "float" in type_name:
            datatype = alc.FLOAT
        elif "int" in type_name:
            datatype = alc.INTEGER
        elif "date" in type_name:
            datatype = alc.DATE
        else:
            datatype = alc.String

        return self._create_column(column_name, datatype)

    def _create_column_from_mongo(self, column_name, form_model, section_model, cde_model):
        column_data_type = self._get_sql_alchemy_datatype(cde_model)
        self._add_reverse_mapping((form_model, section_model, cde_model), column_name)
        if section_model.allow_multiple:
            # This map is used when we unroll/"denormalise" the multisection data
            if section_model.code in self.multisection_column_map:
                self.multisection_column_map[section_model.code].append(column_name)
            else:
                self.multisection_column_map[section_model.code] = [column_name]

        return self._create_column(column_name, column_data_type)

    @timed
    def run_explorer_query(self, database_utils):
        self.create_table()
        self.multisection_unroller.multisection_column_map = self.multisection_column_map
        errors = 0
        for result_dict in database_utils.generate_results(self.reverse_map):
            for unrolled_row in self.multisection_unroller.unroll(result_dict):
                try:
                    self.insert_row(unrolled_row)
                except Exception, ex:
                    errors += 1
                    logger.error("report error: query %s row %s error: %s" % (database_utils.form_object.title,
                                                                              unrolled_row,
                                                                              ex))
        logger.info("query errors: %s" % errors)

    def insert_row(self, value_dict):
        # each row will be a denormalised section item
        self.engine.execute(self.table.insert().values(**value_dict))

    def _create_column(self, name, datatype=alc.String):
        column = alc.Column(name, datatype, nullable=True)
        self.columns.add(column)
        return column

    def create_schema(self):
        self.drop_table()
        logger.debug("creating table schema")
        logger.debug("There are %s columns" % len(self.columns))
        logger.debug("table name will be = %s" % self.table_name)
        self.table = alc.Table(self.table_name, MetaData(self.engine), *self.columns, schema=None)

    def _generate_temporary_table_name(self):
        return "reporting_table" + self.user.username

    def _get_sql_alchemy_datatype(self, cde_model):
        if cde_model.code in self.type_overrides:
            datatype = self.type_overrides[cde_model.code]
        else:
            datatype = cde_model.datatype

        return self.TYPE_MAP.get(datatype, alc.String)

    def dump_csv(self, stream):
        import csv
        writer = csv.writer(stream)
        select_query = alc.sql.select([self.table])
        db_connection = self.engine.connect()
        result = db_connection.execute(select_query)
        writer.writerow(result.keys())
        writer.writerows(result)
        db_connection.close()
        return stream

class MongoFieldSelector(object):
    def __init__(self, user, registry_model, query_model, checkbox_ids=[]):
        if checkbox_ids is not None:
            self.checkbox_ids = checkbox_ids
        else:
            self.checkbox_ids = []

        self.user = user
        self.registry_model = registry_model
        self.query_model = query_model
        if self.query_model:
            self.existing_data = self._get_existing_report_choices(self.query_model)
        else:
            self.existing_data = {}

    def _get_existing_report_choices(self, query_model):
        import json
        try:
            return json.loads(query_model.projection)
        except:
            return []

    @property
    def field_data(self):
        return {"fields": self.fields}

    @property
    def fields(self):
        self.field_info = []
        for form_model in self.registry_model.forms:
            if self.user.can_view(form_model) and not form_model.is_questionnaire:
                for section_model in form_model.section_models:
                    for cde_model in section_model.cde_models:
                        self._get_field_info(form_model, section_model, cde_model)

        return self.field_info

    def _get_saved_value(self, form_model, section_model, cde_model):
        for value_dict in self.existing_data:
            if value_dict["formName"] == form_model.name:
                if value_dict["sectionCode"] == section_model.code:
                    if value_dict["cdeCode"] == cde_model.code:
                        return value_dict["value"]
        return False

    def _get_field_info(self, form_model, section_model, cde_model):
        saved_value = self._get_saved_value(form_model, section_model, cde_model)
        field_id = "cb_%s_%s_%s_%s" % (self.registry_model.code,
                                       form_model.pk,
                                       section_model.pk,
                                       cde_model.pk)
        field_label = cde_model.name
        self.field_info.append({"form": form_model.name,
                                "sectionCode": section_model.code,
                                "sectionName": section_model.display_name,
                                "cdeCode": cde_model.code,
                                "id": field_id,
                                "label": field_label,
                                "savedValue": saved_value})

    @property
    def projections_json(self):
        # this method returns the new projection data back to the client based
        # on the list of checked items passed in
        # the constructed json is independent of db ids ( as these will change
        # is import of registry definition occurs
        import json
        from rdrf.models import Registry, RegistryForm, Section, CommonDataElement
        projected_cdes = []
        for checkbox_id in self.checkbox_ids:
            # <input type="checkbox" name="cb_fh_39_104_CarotidUltrasonography" id="cb_fh_39_104_CarotidUltrasonography">
            # registry code, form pk, section pk, cde_code
            # cb_fh_39_105_EchocardiogramResult
            _, registry_code, form_pk, section_pk, cde_code = checkbox_id.split("_")

            form_model = RegistryForm.objects.get(pk=int(form_pk))
            section_model = Section.objects.get(pk=int(section_pk))
            cde_model = CommonDataElement.objects.get(code=cde_code)

            value_dict = {}
            value_dict["registryCode"] = form_model.registry.code
            value_dict["formName"] = form_model.name
            value_dict["sectionCode"] = section_model.code
            value_dict["cdeCode"] = cde_model.code
            value_dict["value"] = True  # we only need to store the true / checked cdes

            projected_cdes.append(value_dict)

        return json.dumps(projected_cdes)

class ReportTable(object):
    """
    Used by report datatable view
    """

    def __init__(self,  user, query_model):
        self.query_model = query_model
        self.user = user
        self.engine = self._create_engine()
        self.table_name = temporary_table_name(self.query_model, self.user)
        self.table = self._get_table()
        self._converters = {
            "date_of_birth": str,
        }

    @property
    def title(self):
        return "Report Table By Lee"

    @property
    def columns(self):
        return [{"data": col.name, "label": col.name} for col in self.table.columns]

    def _get_table(self):
        return alc.Table(self.table_name, MetaData(self.engine), autoload=True, autoload_with=self.engine)

    def _create_engine(self):
        report_db_data = settings.DATABASES["reporting"]
        db_user = report_db_data["USER"]
        db_pass = report_db_data["PASSWORD"]
        database = report_db_data["NAME"]
        host = report_db_data["HOST"]
        port = report_db_data["PORT"]
        connection_string = "postgresql://{0}:{1}@{2}:{3}/{4}".format(db_user,
                                                                      db_pass,
                                                                      host,
                                                                      port,
                                                                      database)
        return create_engine(connection_string)

    def run_query(self, params=None):
        from sqlalchemy.sql import select
        rows = []
        columns = [col for col in self.table.columns]
        query = select([self.table])
        if params is None:
            pass
        else:
            if "sort_field" in params:
                sort_field = params["sort_field"]
                sort_direction = params["sort_direction"]

                sort_column = getattr(self.table.c, sort_field)
                logger.debug("sorting by %s" % sort_column.name)

                if sort_direction == "asc":
                    logger.debug("sort direction is ascending")
                    sort_column = sort_column.asc()
                else:
                    logger.debug("sort direction is descending")
                    sort_column = sort_column.desc()

                query = query.order_by(sort_column)

        for row in self.engine.execute(query):
                result_dict = {}
                for i, col in enumerate(columns):
                    result_dict[col.name] = self._format(col.name, row[i])
                rows.append(result_dict)
        return rows

    def _format(self, column, data):
        converter = self._converters.get(column, None)
        if converter is None:
            return data
        else:
            return converter(data)

<|endoftext|>


<commit_before>import os
import djcelery
djcelery.setup_loader()

DEBUG = True
TEMPLATE_DEBUG = DEBUG
TASTYPIE_FULL_DEBUG = True

ADMINS = (
    ('Charlie Leifer', 'coleifer@gmail.com'),
    ('Eric Holscher', 'eric@ericholscher.com'),
)

MANAGERS = ADMINS

SITE_ROOT = '/'.join(os.path.dirname(__file__).split('/')[0:-2])
DOCROOT = os.path.join(SITE_ROOT, 'user_builds')
UPLOAD_ROOT = os.path.join(SITE_ROOT, 'user_uploads')
CNAME_ROOT = os.path.join(SITE_ROOT, 'cnames')

MEDIA_ROOT = '%s/media/' % (SITE_ROOT)
MEDIA_URL = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'

CACHE_BACKEND = 'memcached://localhost:11211/'
CACHE_KEY_PREFIX = 'docs'
CACHE_MIDDLEWARE_SECONDS = 60

LOGIN_REDIRECT_URL = '/dashboard/'
FORCE_WWW = False
#APPEND_SLASH = False

TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
USE_I18N = True
SITE_ID = 1
SECRET_KEY = 'asciidick'

ACCOUNT_ACTIVATION_DAYS = 7

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'pagination.middleware.PaginationMiddleware',
    'core.middleware.SubdomainMiddleware',
    #'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)

ROOT_URLCONF = 'urls'

TEMPLATE_DIRS = (
    '%s/readthedocs/templates/' % (SITE_ROOT),
)

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request"
)

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.admin',
    'django.contrib.contenttypes',
    'django.contrib.markup',
    'django.contrib.sessions',
    'django.contrib.sites',

    # third party apps
    'pagination',
    'registration',
    'profiles',
    'taggit',
    'south',
    'basic.flagging',
    'djcelery',
    #'celery_haystack',

    #daniellindsleyrocksdahouse
    'haystack',
    'tastypie',

    # our apps
    'projects',
    'builds',
    'core',
    'rtd_tests',
]

if DEBUG:
    INSTALLED_APPS.append('django_extensions')

#CARROT_BACKEND = "ghettoq.taproot.Database"
CELERY_ALWAYS_EAGER = True
CELERYD_TASK_TIME_LIMIT = 60*60 #60 minutes

DEFAULT_FROM_EMAIL = "no-reply@readthedocs.org"
SESSION_COOKIE_DOMAIN = 'readthedocs.org'

HAYSTACK_SITECONF = 'core.search_sites'
HAYSTACK_SEARCH_ENGINE = 'simple'

AUTH_PROFILE_MODULE = "core.UserProfile"
SOUTH_TESTS_MIGRATE = False

ABSOLUTE_URL_OVERRIDES = {
    'auth.user': lambda o: "/profiles/%s/" % o.username
}

INTERNAL_IPS = ('127.0.0.1',)

backup_count = 1000
if DEBUG:
    backup_count = 2

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
            'datefmt' : "%d/%b/%Y %H:%M:%S"
        },
    },
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'logfile': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': SITE_ROOT + "/rtd.log",
            'maxBytes': 50000,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'errorlog': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': SITE_ROOT + "/rtd.log",
            'maxBytes': 50000,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        },
        'console':{
            'level':'INFO',
            'class':'logging.StreamHandler',
            'formatter': 'standard'
        },
    },
    'loggers': {
        'django': {
            'handlers':['console', 'errorlog'],
            'propagate': True,
            'level':'WARN',
        },
        'django.db.backends': {
            'handlers': ['logfile'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'core': {
            'handlers': ['console', 'logfile'],
            'level': 'DEBUG',
        },
        'api': {
            'handlers': ['console', 'logfile'],
            'level': 'DEBUG',
        },
    }
}

<commit_msg>Send error emails.<commit_after>import os
import djcelery
djcelery.setup_loader()

DEBUG = True
TEMPLATE_DEBUG = DEBUG
TASTYPIE_FULL_DEBUG = True

ADMINS = (
    ('Charlie Leifer', 'coleifer@gmail.com'),
    ('Eric Holscher', 'eric@ericholscher.com'),
)

MANAGERS = ADMINS

SITE_ROOT = '/'.join(os.path.dirname(__file__).split('/')[0:-2])
DOCROOT = os.path.join(SITE_ROOT, 'user_builds')
UPLOAD_ROOT = os.path.join(SITE_ROOT, 'user_uploads')
CNAME_ROOT = os.path.join(SITE_ROOT, 'cnames')

MEDIA_ROOT = '%s/media/' % (SITE_ROOT)
MEDIA_URL = '/media/'
ADMIN_MEDIA_PREFIX = '/media/admin/'

CACHE_BACKEND = 'memcached://localhost:11211/'
CACHE_KEY_PREFIX = 'docs'
CACHE_MIDDLEWARE_SECONDS = 60

LOGIN_REDIRECT_URL = '/dashboard/'
FORCE_WWW = False
#APPEND_SLASH = False

TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
USE_I18N = True
SITE_ID = 1
SECRET_KEY = 'asciidick'

ACCOUNT_ACTIVATION_DAYS = 7

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'pagination.middleware.PaginationMiddleware',
    'core.middleware.SubdomainMiddleware',
    #'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)

ROOT_URLCONF = 'urls'

TEMPLATE_DIRS = (
    '%s/readthedocs/templates/' % (SITE_ROOT),
)

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request"
)

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.admin',
    'django.contrib.contenttypes',
    'django.contrib.markup',
    'django.contrib.sessions',
    'django.contrib.sites',

    # third party apps
    'pagination',
    'registration',
    'profiles',
    'taggit',
    'south',
    'basic.flagging',
    'djcelery',
    #'celery_haystack',

    #daniellindsleyrocksdahouse
    'haystack',
    'tastypie',

    # our apps
    'projects',
    'builds',
    'core',
    'rtd_tests',
]

if DEBUG:
    INSTALLED_APPS.append('django_extensions')

#CARROT_BACKEND = "ghettoq.taproot.Database"
CELERY_ALWAYS_EAGER = True
CELERYD_TASK_TIME_LIMIT = 60*60 #60 minutes
CELERY_SEND_TASK_ERROR_EMAILS = True

DEFAULT_FROM_EMAIL = "no-reply@readthedocs.org"
SESSION_COOKIE_DOMAIN = 'readthedocs.org'

HAYSTACK_SITECONF = 'core.search_sites'
HAYSTACK_SEARCH_ENGINE = 'simple'

AUTH_PROFILE_MODULE = "core.UserProfile"
SOUTH_TESTS_MIGRATE = False

ABSOLUTE_URL_OVERRIDES = {
    'auth.user': lambda o: "/profiles/%s/" % o.username
}

INTERNAL_IPS = ('127.0.0.1',)

backup_count = 1000
if DEBUG:
    backup_count = 2

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
            'datefmt' : "%d/%b/%Y %H:%M:%S"
        },
    },
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'logfile': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': SITE_ROOT + "/rtd.log",
            'maxBytes': 50000,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'errorlog': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': SITE_ROOT + "/rtd.log",
            'maxBytes': 50000,
            'backupCount': backup_count,
            'formatter': 'standard',
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        },
        'console':{
            'level':'INFO',
            'class':'logging.StreamHandler',
            'formatter': 'standard'
        },
    },
    'loggers': {
        'django': {
            'handlers':['console', 'errorlog'],
            'propagate': True,
            'level':'WARN',
        },
        'django.db.backends': {
            'handlers': ['logfile'],
            'level': 'DEBUG',
            'propagate': False,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'core': {
            'handlers': ['console', 'logfile'],
            'level': 'DEBUG',
        },
        'api': {
            'handlers': ['console', 'logfile'],
            'level': 'DEBUG',
        },
    }
}

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import discord
from discord.ext import commands
import asyncio
import sys
import logging
import aiohttp
import json
import textwrap
from subprocess import check_output
from other import ownerchecks
from random import choice as rchoice
logging.basicConfig(format='[%(levelname)s] - %(message)s', level=logging.INFO)
description = '''beep boop :)'''
bot = commands.Bot(command_prefix='^', description=description)
config = json.loads(open('config.json').read())

@bot.command()
async def k():
  """k"""
  await bot.say('k')

@bot.command()
async def fuck():
  """fuck"""
  await bot.say('fuck')

@bot.command()
async def ping():
  """Ping? Pong."""
  em = discord.Embed(title='Pong!', description='I am currently alive.', colour=0x6906E8)
  em.set_author(name='lolbot')
  await bot.say(embed=em)

@bot.command()
async def about():
  """Information about lolbot."""
  em = discord.Embed(title='lolbot', description='Written by lold. (c) 2017 lold, all rights reserved.\nDiscord.py version: ' + discord.__version__ + '\nPython version: ' + sys.version + '\nWant to support lolbot and other projects? Donate to my ko-fi (https://ko-fi.com/A753OUG) or PayPal.me (https://paypal.me/ynapw)', colour=0x6906E8)
  em.set_author(name='lolbot, written by lold')
  await bot.say(embed=em)

@bot.command(pass_context=True)
async def suggest( ctx, *, suggestion: str ):
  """Got suggestions?"""
  await bot.say('Feedback has been forwarded on to the mailbox.')
  await bot.say(config['sugchannel'], 'Suggestion submitted: `' + str(suggestion) + '`')

@bot.command()
async def cat():
  """Random cat images. Awww, so cute! Powered by random.cat"""
  with aiohttp.ClientSession() as session:
    async with session.get('https://random.cat/meow') as r:
      if r.status == 200:
        js = await r.json()
        em = discord.Embed(name='random.cat', colour=0x6906E8)
        em.set_image(url=js['file'])
        await bot.say(embed=em)

@bot.command()
async def echo(*, message: str):
  """Self-explanatory."""
  await bot.say(message)

@bot.command()
async def httpcat(*, http_id: str):
  """http.cat images - ^httpcat <http code>"""
  httpcat_em = discord.Embed(name='http.cat', colour=0x6906E8)
  httpcat_em.set_image(url='https://http.cat/' + http_id + '.jpg')
  await bot.say(embed=httpcat_em)

# slice's eval code :^)
@bot.command(hidden=True, pass_context=True)
@ownerchecks.is_owner()
async def evalboi(self, ctx, *, code: str):
  """Because everyone needs a good eval once in a while."""
  env = {
    'bot': ctx.bot,
    'ctx': ctx,
    'msg': ctx.message,
    'guild': ctx.guild,
    'channel': ctx.channel,
    'me': ctx.message.author,
    'get': discord.utils.get,
    'find': discord.utils.find,
  }

  fmt_exception = '```py\n>>> {}\n\n{}: {}```'

  env.update(globals())

  indented_code = textwrap.indent(code, '    ')
  wrapped_code = 'async def _eval_code():\n' + indented_code
  try:
      exec(wrapped_code, env)
      return_value = await env['_eval_code']()
      if return_value is not None:
        await ctx.send(return_value)
  except Exception as e:
      name = type(e).__name__
      await ctx.send(fmt_exception.format(code, name, e))
      return
@bot.command(hidden=True)
@ownerchecks.is_owner()
async def reboot():
  """Duh. Owner only"""
  await bot.say('Second please.')
  logging.info('Restart requested')
  await bot.change_presence(game=discord.Game(name='Restarting'))
  try:
    check_output(['sh', 'bot.sh'])
  except:
    await bot.say('ERROR: fix your fucking code pls')
  else:
    await bot.logout()

@bot.command(hidden=True)
@ownerchecks.is_owner()
async def game(*, game: str):
  """Changes playing status"""
  await bot.change_presence(game=discord.Game(name=game + ' | ^help | v3.0'))

@bot.command()
async def shibe():
  """Random shibes, powered by shibe.online"""
  with aiohttp.ClientSession() as shibe:
    async with shibe.get('http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true') as shibeGet:
      if shibeGet.status == 200:
        shibeJson = await shibeGet.json()
        shibeEmbed = discord.Embed(name='shibe.online', colour=0x6906E8)
        shibeEmbed.set_image(url=shibeJson[0])
        await bot.say(embed=shibeEmbed)

@bot.command()
async def stats():
  """A few stats."""
  statEmbed = discord.Embed(name='lolbot stats', description='```\nServers: ' + str(len(bot.servers)) + '', colour=0x690E8)
  await bot.say(embed=statEmbed)

@bot.command(name='8ball')
async def an8ball(*, question: str):
  pool = ['It is certain', 'Outlook good', 'You may rely on it', 'Ask again later', 'Concentrate and ask again', 'Reply hazy, try again', 'My reply is no', 'My sources say no']
  ans = rchoice(pool)
  emb = discord.Embed(name='The Magic 8-ball', description='**Question: ' + str(question) + '\nAnswer: ' + str(8answer), colour=0x690E8)
  await bot.say(embed=emb)

@bot.event()
async def on_server_join( server ):
  logging.info('Joined server' + str(server.name))
  logging.info('Server ID' + str(server.id))

# danny code frankenstein :P
async def botstats():
  while True:
    async with aiohttp.ClientSession() as session:
      payload = json.dumps({
        'server_count': len(bot.servers)
      })

      headers = {
        'authorization': config['dbots'],
        'content-type': 'application/json'
      }
      dbl_headers = {
        'authorization': config['dbl'],
        'content-type': 'application/json'
      }

      dbots_url = 'https://bots.discord.pw/api/bots/' + config['botid'] + '/stats'
      dbl_url = 'https://discordbots.org/api/bots/' + config['botid'] + '/stats'
      async with session.post(dbl_url, data=payload, headers=dbl_headers) as dbl_resp:
        logging.info('dbl: posted with code' + str(dbl_resp.status))
      async with session.post(dbots_url, data=payload, headers=headers) as resp:
        logging.info('dbots: posted with code' + str(resp.status))
      await asyncio.sleep(3600) # report to DBL/dbots every hour

try:
  @bot.event
  async def on_ready():
    logging.info('lolbot - ready')
    loop = asyncio.get_event_loop()
    serverpoll = loop.create_task(botstats())
    logging.info('Bot post loop initalized')
    await bot.change_presence(game=discord.Game(name='with APIs. | ^help | v3.0'))
    logging.info('Playing status changed')
except ImportError:
  logging.warn('Module(s) could not be found/not installed')
  logging.warn('Installing automatically')
  check_output(['pip', 'install', '-r', 'requirements.txt'])
  sys.exit('Please relaunch lolbot')

try:
  bot.run(config['token'])
except FileNotFoundError:
  logging.error('I can not find config.json!')
  logging.error('Are you sure you are in the same folder as it?')
<commit_msg>[8ball, stats] oh god<commit_after># -*- coding: utf-8 -*-
import discord
from discord.ext import commands
import asyncio
import sys
import logging
import aiohttp
import json
import textwrap
from subprocess import check_output
from other import ownerchecks
from random import choice as rchoice
logging.basicConfig(format='[%(levelname)s] - %(message)s', level=logging.INFO)
description = '''beep boop :)'''
bot = commands.Bot(command_prefix='^', description=description)
config = json.loads(open('config.json').read())

@bot.command()
async def k():
  """k"""
  await bot.say('k')

@bot.command()
async def fuck():
  """fuck"""
  await bot.say('fuck')

@bot.command()
async def ping():
  """Ping? Pong."""
  em = discord.Embed(title='Pong!', description='I am currently alive.', colour=0x6906E8)
  em.set_author(name='lolbot')
  await bot.say(embed=em)

@bot.command()
async def about():
  """Information about lolbot."""
  em = discord.Embed(title='lolbot', description='Written by lold. (c) 2017 lold, all rights reserved.\nDiscord.py version: ' + discord.__version__ + '\nPython version: ' + sys.version + '\nWant to support lolbot and other projects? Donate to my ko-fi (https://ko-fi.com/A753OUG) or PayPal.me (https://paypal.me/ynapw)', colour=0x6906E8)
  em.set_author(name='lolbot, written by lold')
  await bot.say(embed=em)

@bot.command(pass_context=True)
async def suggest( ctx, *, suggestion: str ):
  """Got suggestions?"""
  await bot.say('Feedback has been forwarded on to the mailbox.')
  await bot.say(config['sugchannel'], 'Suggestion submitted: `' + str(suggestion) + '`')

@bot.command()
async def cat():
  """Random cat images. Awww, so cute! Powered by random.cat"""
  with aiohttp.ClientSession() as session:
    async with session.get('https://random.cat/meow') as r:
      if r.status == 200:
        js = await r.json()
        em = discord.Embed(name='random.cat', colour=0x6906E8)
        em.set_image(url=js['file'])
        await bot.say(embed=em)

@bot.command()
async def echo(*, message: str):
  """Self-explanatory."""
  await bot.say(message)

@bot.command()
async def httpcat(*, http_id: str):
  """http.cat images - ^httpcat <http code>"""
  httpcat_em = discord.Embed(name='http.cat', colour=0x6906E8)
  httpcat_em.set_image(url='https://http.cat/' + http_id + '.jpg')
  await bot.say(embed=httpcat_em)

# slice's eval code :^)
@bot.command(hidden=True, pass_context=True)
@ownerchecks.is_owner()
async def evalboi(self, ctx, *, code: str):
  """Because everyone needs a good eval once in a while."""
  env = {
    'bot': ctx.bot,
    'ctx': ctx,
    'msg': ctx.message,
    'guild': ctx.guild,
    'channel': ctx.channel,
    'me': ctx.message.author,
    'get': discord.utils.get,
    'find': discord.utils.find,
  }

  fmt_exception = '```py\n>>> {}\n\n{}: {}```'

  env.update(globals())

  indented_code = textwrap.indent(code, '    ')
  wrapped_code = 'async def _eval_code():\n' + indented_code
  try:
      exec(wrapped_code, env)
      return_value = await env['_eval_code']()
      if return_value is not None:
        await ctx.send(return_value)
  except Exception as e:
      name = type(e).__name__
      await ctx.send(fmt_exception.format(code, name, e))
      return
@bot.command(hidden=True)
@ownerchecks.is_owner()
async def reboot():
  """Duh. Owner only"""
  await bot.say('Second please.')
  logging.info('Restart requested')
  await bot.change_presence(game=discord.Game(name='Restarting'))
  try:
    check_output(['sh', 'bot.sh'])
  except:
    await bot.say('ERROR: fix your fucking code pls')
  else:
    await bot.logout()

@bot.command(hidden=True)
@ownerchecks.is_owner()
async def game(*, game: str):
  """Changes playing status"""
  await bot.change_presence(game=discord.Game(name=game + ' | ^help | v3.0'))

@bot.command()
async def shibe():
  """Random shibes, powered by shibe.online"""
  with aiohttp.ClientSession() as shibe:
    async with shibe.get('http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true') as shibeGet:
      if shibeGet.status == 200:
        shibeJson = await shibeGet.json()
        shibeEmbed = discord.Embed(name='shibe.online', colour=0x6906E8)
        shibeEmbed.set_image(url=shibeJson[0])
        await bot.say(embed=shibeEmbed)

@bot.command()
async def stats():
  """A few stats."""
  statEmbed = discord.Embed(title='lolbot stats', description='```\nServers: ' + str(len(bot.servers)) + '', colour=0x690E8)
  await bot.say(embed=statEmbed)

@bot.command(name='8ball')
async def an8ball(*, question: str):
  pool = ['It is certain', 'Outlook good', 'You may rely on it', 'Ask again later', 'Concentrate and ask again', 'Reply hazy, try again', 'My reply is no', 'My sources say no']
  ans = rchoice(pool)
  emb = discord.Embed(title='The Magic 8-ball', description='**Question: ' + str(question) + '\nAnswer: ' + str(8answer), colour=0x690E8)
  await bot.say(embed=emb)

@bot.event()
async def on_server_join( server ):
  logging.info('Joined server' + str(server.name))
  logging.info('Server ID' + str(server.id))

# danny code frankenstein :P
async def botstats():
  while True:
    async with aiohttp.ClientSession() as session:
      payload = json.dumps({
        'server_count': len(bot.servers)
      })

      headers = {
        'authorization': config['dbots'],
        'content-type': 'application/json'
      }
      dbl_headers = {
        'authorization': config['dbl'],
        'content-type': 'application/json'
      }

      dbots_url = 'https://bots.discord.pw/api/bots/' + config['botid'] + '/stats'
      dbl_url = 'https://discordbots.org/api/bots/' + config['botid'] + '/stats'
      async with session.post(dbl_url, data=payload, headers=dbl_headers) as dbl_resp:
        logging.info('dbl: posted with code' + str(dbl_resp.status))
      async with session.post(dbots_url, data=payload, headers=headers) as resp:
        logging.info('dbots: posted with code' + str(resp.status))
      await asyncio.sleep(3600) # report to DBL/dbots every hour

try:
  @bot.event
  async def on_ready():
    logging.info('lolbot - ready')
    loop = asyncio.get_event_loop()
    serverpoll = loop.create_task(botstats())
    logging.info('Bot post loop initalized')
    await bot.change_presence(game=discord.Game(name='with APIs. | ^help | v3.0'))
    logging.info('Playing status changed')
except ImportError:
  logging.warn('Module(s) could not be found/not installed')
  logging.warn('Installing automatically')
  check_output(['pip', 'install', '-r', 'requirements.txt'])
  sys.exit('Please relaunch lolbot')

try:
  bot.run(config['token'])
except FileNotFoundError:
  logging.error('I can not find config.json!')
  logging.error('Are you sure you are in the same folder as it?')
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import discord
from discord.ext import commands
import asyncio
import sys
import logging
import aiohttp
import json
import textwrap
from subprocess import check_output
from other import ownerchecks

logging.basicConfig(level=logging.INFO)
description = '''beep boop :)'''
bot = commands.Bot(command_prefix='^', description=description)
config = json.loads(open('config.json').read())

@bot.command()
async def k():
  """k"""
  await bot.say('k')

@bot.command()
async def fuck():
  """fuck"""
  await bot.say('fuck')

@bot.command()
async def ping():
  """Ping? Pong."""
  em = discord.Embed(title='Pong!', description='I am currently alive.', colour=0x6906E8)
  em.set_author(name='lolbot', icon_url=bot.user.default_avatar_url)
  await bot.say(embed=em)

@bot.command()
async def about():
  """Information about lolbot."""
  em = discord.Embed(title='lolbot version 1.0', description='Written by lold. (c) 2017 lold, all rights reserved.\nDiscord.py version: ' + discord.__version__ + '\nPython version: ' + sys.version + '\nWant to support lolbot and other projects? Donate to my ko-fi (https://ko-fi.com/A753OUG) or PayPal.me (https://paypal.me/ynapw)', colour=0x6906E8)
  em.set_author(name='lolbot, written by lold', icon_url=bot.user.default_avatar_url)
  await bot.say(embed=em)

@bot.command(pass_context=True)
async def suggest( ctx, *, suggestion: str ):
  """Got suggestions?"""
  await bot.say('Feedback has been forwarded on to the mailbox.')
  await bot.say(config['sugchannel'], 'Suggestion submitted: `' + str(suggestion) + '`')

@bot.command()
async def cat():
  with aiohttp.ClientSession() as session:
    """Random cat images. Awww, so cute! Powered by random.cat"""
    async with session.get('https://random.cat/meow') as r:
      if r.status == 200:
        js = await r.json()
        em = discord.Embed(title='lolbot', description='Here is your cat image, as requested.', colour=0x6906E8)
        em.set_author(name='lolbot', icon_url=bot.user.default_avatar_url)
        em.set_image(url=js['file'])
        await bot.say(embed=em)

@bot.command()
async def echo(*, message: str):
  """Self-explanatory."""
  await bot.say(message)

@bot.command()
async def httpcat(*, http_id: str):
  """http.cat images - ^httpcat <http code>"""
  httpcat_em = discord.Embed(title='lolbot', description='http.cat - here is your picture!', colour=0x6906E8)
  httpcat_em.set_image(url='https://http.cat/' + http_id + '.jpg')
  await bot.say(embed=httpcat_em)

# slice's eval code :^)
@bot.command(hidden=True, pass_context=True)
@ownerchecks.is_owner()
async def eval(self, ctx, *, code: str):
  """Because everyone needs a good eval once in a while."""
  env = {
    'bot': ctx.bot,
    'ctx': ctx,
    'msg': ctx.message,
    'guild': ctx.guild,
    'channel': ctx.channel,
    'me': ctx.message.author,
    'get': discord.utils.get,
    'find': discord.utils.find,
  }

  fmt_exception = '```py\n>>> {}\n\n{}: {}```'

  env.update(globals())

  indented_code = textwrap.indent(code, '    ')
  wrapped_code = 'async def _eval_code():\n' + indented_code
  try:
      exec(wrapped_code, env)
      return_value = await env['_eval_code']()
      if return_value is not None:
        await ctx.send(return_value)
  except Exception as e:
      name = type(e).__name__
      await ctx.send(fmt_exception.format(code, name, e))
      return
@bot.command(hidden=True)
@ownerchecks.is_owner()
async def reboot():
  """Duh. Owner only"""
  await bot.say('Second please.')
  logging.info('Restart requested')
  await bot.change_presence(game=discord.Game(name='Restarting'))
  check_output(['sh', 'bot.sh'])
  await bot.logout()

@bot.command(hidden=True)
@ownerchecks.is_owner()
async def game(*, game: str):
  """Changes playing status"""
  await bot.change_presence(game=discord.Game(name=game + ' | ^help | v2.0'))

@bot.command()
async def shibe():
  with aiohttp.ClientSession() as shibe:
    """Random shibes, powered by shibe.online"""
    async with shibe.get('http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true') as shibeGet:
      if shibeGet.status == 200:
        shibeJson = await shibeGet.json()
        shibeEmbed = discord.Embed(name='shibe.online', colour=0x6906E8)
        shibeEmbed.set_image(url=shibeJson[0])
        await bot.say(embed=shibeEmbed)

@bot.event
async def on_server_join( server ):
  logging.info('Joined server' + str(server.name))
  logging.info('Server ID' + str(server.id))

async def botstats():
  async with aiohttp.ClientSession() as self.session:
    payload = json.dumps({
      'server_count': len(bot.servers)
    })

    headers = {
      'authorization': config['dbots'],
      'content-type': 'application/json'
    }
    dbl_headers = {
      'authorization': config['dbl'],
      'content-type': 'application/json'
    }

    dbots_url = 'https://bots.discord.pw/api/bots' + config['botid'] + 'stats'
    dbl_url = 'https://discordbots.org/api/bots' + config['botid'] + 'stats'
    async with self.session.post(dbl_url, data=payload, headers=dbl_headers) as dbl_resp:
      logging.info('dbl: posted with code' + await resp.status())
    async with self.session.post(dbots_url, data=payload, headers=headers) as resp:
      logging.info('dbots: posted with code' + await resp.status())
    await asyncio.sleep(60 * 60) # report to DBL/dbots every hour

try:
  @bot.event
  async def on_ready():
    logging.info('lolbot - ready')
    loop = asyncio.get_event_loop()
    serverpoll = loop.create_task(botstats())
    logging.info('Bot post loop initalized')
    await bot.change_presence(game=discord.Game(name='with APIs. | ^help | v2.0'))
    logging.info('Playing status changed')
except ImportError:
  logging.warn('Module(s) could not be found/not installed')
  logging.warn('Installing automatically')
  check_output(['pip', 'install', '-r', 'requirements.txt'])
  sys.exit('Please relaunch lolbot')

try:
  bot.run(config['token'])
except FileNotFoundError:
  logging.error('I can not find config.json!')
  logging.error('Are you sure you are in the same folder as it?')

<commit_msg>[stats] s e l f<commit_after># -*- coding: utf-8 -*-
import discord
from discord.ext import commands
import asyncio
import sys
import logging
import aiohttp
import json
import textwrap
from subprocess import check_output
from other import ownerchecks

logging.basicConfig(level=logging.INFO)
description = '''beep boop :)'''
bot = commands.Bot(command_prefix='^', description=description)
config = json.loads(open('config.json').read())

@bot.command()
async def k():
  """k"""
  await bot.say('k')

@bot.command()
async def fuck():
  """fuck"""
  await bot.say('fuck')

@bot.command()
async def ping():
  """Ping? Pong."""
  em = discord.Embed(title='Pong!', description='I am currently alive.', colour=0x6906E8)
  em.set_author(name='lolbot', icon_url=bot.user.default_avatar_url)
  await bot.say(embed=em)

@bot.command()
async def about():
  """Information about lolbot."""
  em = discord.Embed(title='lolbot version 1.0', description='Written by lold. (c) 2017 lold, all rights reserved.\nDiscord.py version: ' + discord.__version__ + '\nPython version: ' + sys.version + '\nWant to support lolbot and other projects? Donate to my ko-fi (https://ko-fi.com/A753OUG) or PayPal.me (https://paypal.me/ynapw)', colour=0x6906E8)
  em.set_author(name='lolbot, written by lold', icon_url=bot.user.default_avatar_url)
  await bot.say(embed=em)

@bot.command(pass_context=True)
async def suggest( ctx, *, suggestion: str ):
  """Got suggestions?"""
  await bot.say('Feedback has been forwarded on to the mailbox.')
  await bot.say(config['sugchannel'], 'Suggestion submitted: `' + str(suggestion) + '`')

@bot.command()
async def cat():
  with aiohttp.ClientSession() as session:
    """Random cat images. Awww, so cute! Powered by random.cat"""
    async with session.get('https://random.cat/meow') as r:
      if r.status == 200:
        js = await r.json()
        em = discord.Embed(title='lolbot', description='Here is your cat image, as requested.', colour=0x6906E8)
        em.set_author(name='lolbot', icon_url=bot.user.default_avatar_url)
        em.set_image(url=js['file'])
        await bot.say(embed=em)

@bot.command()
async def echo(*, message: str):
  """Self-explanatory."""
  await bot.say(message)

@bot.command()
async def httpcat(*, http_id: str):
  """http.cat images - ^httpcat <http code>"""
  httpcat_em = discord.Embed(title='lolbot', description='http.cat - here is your picture!', colour=0x6906E8)
  httpcat_em.set_image(url='https://http.cat/' + http_id + '.jpg')
  await bot.say(embed=httpcat_em)

# slice's eval code :^)
@bot.command(hidden=True, pass_context=True)
@ownerchecks.is_owner()
async def eval(self, ctx, *, code: str):
  """Because everyone needs a good eval once in a while."""
  env = {
    'bot': ctx.bot,
    'ctx': ctx,
    'msg': ctx.message,
    'guild': ctx.guild,
    'channel': ctx.channel,
    'me': ctx.message.author,
    'get': discord.utils.get,
    'find': discord.utils.find,
  }

  fmt_exception = '```py\n>>> {}\n\n{}: {}```'

  env.update(globals())

  indented_code = textwrap.indent(code, '    ')
  wrapped_code = 'async def _eval_code():\n' + indented_code
  try:
      exec(wrapped_code, env)
      return_value = await env['_eval_code']()
      if return_value is not None:
        await ctx.send(return_value)
  except Exception as e:
      name = type(e).__name__
      await ctx.send(fmt_exception.format(code, name, e))
      return
@bot.command(hidden=True)
@ownerchecks.is_owner()
async def reboot():
  """Duh. Owner only"""
  await bot.say('Second please.')
  logging.info('Restart requested')
  await bot.change_presence(game=discord.Game(name='Restarting'))
  check_output(['sh', 'bot.sh'])
  await bot.logout()

@bot.command(hidden=True)
@ownerchecks.is_owner()
async def game(*, game: str):
  """Changes playing status"""
  await bot.change_presence(game=discord.Game(name=game + ' | ^help | v2.0'))

@bot.command()
async def shibe():
  with aiohttp.ClientSession() as shibe:
    """Random shibes, powered by shibe.online"""
    async with shibe.get('http://shibe.online/api/shibes?count=1&urls=true&httpsUrls=true') as shibeGet:
      if shibeGet.status == 200:
        shibeJson = await shibeGet.json()
        shibeEmbed = discord.Embed(name='shibe.online', colour=0x6906E8)
        shibeEmbed.set_image(url=shibeJson[0])
        await bot.say(embed=shibeEmbed)

@bot.event
async def on_server_join( server ):
  logging.info('Joined server' + str(server.name))
  logging.info('Server ID' + str(server.id))

async def botstats(self):
  async with aiohttp.ClientSession() as self.session:
    payload = json.dumps({
      'server_count': len(bot.servers)
    })

    headers = {
      'authorization': config['dbots'],
      'content-type': 'application/json'
    }
    dbl_headers = {
      'authorization': config['dbl'],
      'content-type': 'application/json'
    }

    dbots_url = 'https://bots.discord.pw/api/bots' + config['botid'] + 'stats'
    dbl_url = 'https://discordbots.org/api/bots' + config['botid'] + 'stats'
    async with self.session.post(dbl_url, data=payload, headers=dbl_headers) as dbl_resp:
      logging.info('dbl: posted with code' + await resp.status())
    async with self.session.post(dbots_url, data=payload, headers=headers) as resp:
      logging.info('dbots: posted with code' + await resp.status())
    await asyncio.sleep(60 * 60) # report to DBL/dbots every hour

try:
  @bot.event
  async def on_ready():
    logging.info('lolbot - ready')
    loop = asyncio.get_event_loop()
    serverpoll = loop.create_task(botstats())
    logging.info('Bot post loop initalized')
    await bot.change_presence(game=discord.Game(name='with APIs. | ^help | v2.0'))
    logging.info('Playing status changed')
except ImportError:
  logging.warn('Module(s) could not be found/not installed')
  logging.warn('Installing automatically')
  check_output(['pip', 'install', '-r', 'requirements.txt'])
  sys.exit('Please relaunch lolbot')

try:
  bot.run(config['token'])
except FileNotFoundError:
  logging.error('I can not find config.json!')
  logging.error('Are you sure you are in the same folder as it?')

<|endoftext|>


<commit_before>import concurrent.futures
import copy
from enum import Enum
from functools import partial
import os
from platform import system as system_name
import PySide.QtCore as QtCore
from PySide.QtCore import QDir
from PySide.QtCore import QPoint
from PySide.QtCore import QSize
import PySide.QtGui as QtGui
import random
import sys
import threading
import yaml

CLIENTFILE__ = 'clients.yaml'
OTREE_EXEC__ = 'chrome.exe'
ORG__ = 'Alfred-Weber-Institut für Wirtschaftwissenschaften'
NAME__ = 'AWIDominator'
PSEXEC__ = '.\psexec.exe'
BROADCAST_IP__ = '255.255.255.255'

def sendWarning(text):
    # TODO(d1): docstring
    warnBox = QtGui.QMessageBox()
    warnBox.setWindowTitle('Warnung!')
    warnBox.setText(text)
    warnBox.setStandardButtons(QtGui.QMessageBox.Ok)
    return warnBox.exec_() == QtGui.QMessageBox.Ok

def sendBooleanQuery(text):
    # TODO(d1): docstring
    questionBox = QtGui.QMessageBox()
    questionBox.setWindowTitle('Achtung!')
    questionBox.setText(text)
    questionBox.setStandardButtons(QtGui.QMessageBox.Yes)
    questionBox.addButton(QtGui.QMessageBox.No)
    questionBox.setDefaultButton(QtGui.QMessageBox.No)
    return questionBox.exec_() == QtGui.QMessageBox.Yes

class Ternary(Enum):
    # TODO(d1): docstring
    OFF = 0
    ON = 1
    UNKNOWN = 2

class AWIDom(QtGui.QApplication):
    """Handles the whole program."""

    def __init__(self, cfile=CLIENTFILE__):
        """
        Consturct a AWIDOM

        Args:
            cfile (string, optional): The path to the configuration file.
        """
        super().__init__(sys.argv)
        self.setOrganizationName(ORG__)
        self.setApplicationName(NAME__)
        self.left = PCList('Linke Seite')
        self.right = PCList('Rechte Seite')
        self.otree_uri = ''
        self.loadConfig(cfile)
        self.createWindow()

    def loadConfig(self, cfile):
        """Loads a configuration file and fills the memebers accordingly.

        Args:
            cfile (string): The path to the configuration file
        """
        with open(cfile, 'r') as f:
            try:
                clientsconf = yaml.load(f)
                self.loadPCs(self.left, clientsconf['left'])
                self.loadPCs(self.right, clientsconf['right'])
                self.otree_uri = clientsconf['otree-uri']
            except yaml.YAMLError as e:
                print(e)
                sendWarning('Configuration couldn\'t be loaded')
                sys.exit()

    def loadPCs(self, target, confs):
        """Goes throgh a list of PCs from a conf file and appends them to a
        PCList.

        Args:
            target (PCList): A PCList to append the new PCs to.
            confs (list): A list of PCs in dict form
        """
        return [target.append(PC(c['id'], c['name'], c['ip'], c['mac'])),
                for c in confs]

    def createWindow(self):
        """Creates the window for the application without showing/displaying it.
        """
        self.mainwindow = MainWindow()
        self.mainwindow.createLayout()
        self.mainwindow.pclistswidget.addList(self.left)
        self.mainwindow.pclistswidget.addList(self.right)

    def run(self):
        """Showing the constructed window to the user."""
        self.mainwindow.show()

class PC(QtGui.QCheckBox):
    """Handles one PC in the lab"""

    def __init__(self, id, name, ip, mac):
        """Initalizes the PC

        Args:
            id (int): The id for this PC
            name (str): A string as identifier
            ip (str): The IPv4-address
            mac (str): the MAC-address of this PC
        """
        super().__init__(name)
        self.id = id
        self.name = name
        self.ip = ip
        self.setMac(mac)
        self.online = Ternary(Ternary.UNKNOWN)
        self.isPinging = False
        self.loadIcons()

    def __lt__(self, other):
        """Less then comparison operator

        Args:
            other (PC): The other PC
        Returns:
            self.id < other.id
        """
        return self.id < other.id

    def __repr__(self):
        """Representation of a PC"""
        return repr((self.id, self.name, self.ip, self.mac))

    def __str__(self):
        """Nice formatted string output for a PC"""
        return ('PC: [id: {}, name: {}, ip: {}, mac: {}]'
                ''.format(self.id, self.name, self.ip, self.mac))

    def loadIcons(self):
        # TODO(d1): docstring
        pixmap_on = QtGui.QPixmap('./assets/font_awesome_toggle_on.png')
        pixmap_off = QtGui.QPixmap('./assets/font_awesome_toggle_off.png')
        pixmap_question = QtGui.QPixmap('./assets/font_awesome_question.png')
        self._icon_on = QtGui.QIcon(pixmap_on)
        self._icon_off = QtGui.QIcon(pixmap_off)
        self._icon_question = QtGui.QIcon(pixmap_question)

    def setMac(mac):
        if len(mac) == 12:
            pass
        elif len(mac) == 12 + 5:
            sep = mac[2]
            mac = mac.replace(sep, '')
        else:
            raise ValueError('Incorrect MAC address format')
        self.mac = mac

    def setOnline(self, status):
        # TODO(d1): docstring
        self.online = status
        self.setOnlineIcon()

    def setOnlineIcon(self):
        # TODO(d1): docstring
        if self.online == Ternary.ON:
            self.setIcon(self._icon_on)
        elif self.online == Ternary.OFF:
            self.setIcon(self._icon_off)
        else:
            self.setIcon(self._icon_question)
        self.setIconSize(QtCore.QSize(16, 16))

    def _ping(self):
        """Ping this PC"""
        self.isPinging = True
        self.setOnline(Ternary.UNKNOWN)
        ping_param = '-n 1' if system_name().lower() == 'windows' else '-c 1'
        isOnline = os.system('ping {} {}'.format(ping_param, self.ip)) == 0
        if isOnline:
            self.setOnline(Ternary.ON)
        else:
            self.setOnline(Ternary.OFF)
        self.isPinging = False
        return isOnline

    def ping(self):
        # TODO(d1): docstring
        if not self.isPinging:
            ping_thread = threading.Thread(target=self._ping)
            ping_thread.start()

    def _wake(host):
        # TODO(d1): docstring
        # Pad the synchronization stream.
        data = ''.join(['FFFFFFFFFFFF', self.mac * 20])
        send_data = b''

        # Split up the hex values and pack.
        for i in range(0, len(data), 2):
            send_data = b''.join([send_data,
                                  struct.pack('B', int(data[i: i + 2], 16))])

        # Broadcast it to the LAN.
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.sendto(send_data, (BROADCAST_IP__, 7))
        return True

    def wake(self):
        # TODO(d1): docstring
        if not self.isChecked():
            return True
        if self.online != Ternary.ON:
            self._wake()
            self.setOnline(Ternary.UNKNOWN)
            # self.checked = False
        else:
            sendWarning('{} is already alive.'.format(self.name))

    def execCommand(self, command):
        # TODO(d1): docstring
        if not self.isChecked():
            return True
        if self.online == Ternary.ON:
            self.setChecked(False)
            print('Executing {} on {}'.format(command, self.name))
        else:
            sendWarning('{} is not alive.'.format(self.name))

class PCList(QtGui.QGroupBox):
    """A List of Buttons/Models of PCs, used to display as a list."""

    def __init__(self, title, pc_list=None):
        """Consturcts a new PCList.

        Args:
            title (str): The Title for the list, will be shown.
            pc_list (list, optional): The List of PCs added to the object.
        """
        super().__init__(title)
        self.layout = QtGui.QVBoxLayout()
        self.setSelectAllButton()
        if pc_list is not None:
            self.load(pc_list)

    def __iter__(self):
        return iter(self.children())

    def setSelectAllButton(self):
        self.selectall = QtGui.QPushButton('Select all')
        self.selectall.clicked.connect(self.selectAll)
        self.append(self.selectall)

    def load(self, pc_list):
        """Append all PCs in a list to this PCList.

        Args:
            pc_list (list): A list of PCs.
        """
        return [self.append(pc) for pc in pc_list]

    def append(self, item):
        """Append a single item to the List:

        Args:
            item (QWidget): The item.
        """
        self.layout.addWidget(item)
        if isinstance(item, PC):
            item.ping()
            self.layout.removeWidget(self.selectall)
            self.layout.addWidget(self.selectall)
        self.setLayout(self.layout)

    def selectAll(self):
        # TODO(d1): docstring
        return [i.setChecked() for i in self if isinstance(i, PC)]

    def wake(self):
        # TODO(d1): docstring
        return [i.wake() for i in self if isinstance(i, PC)]

    def execCommand(self, command):
        # TODO(d1): docstring
        return [i.execCommand(command) for i in self if isinstance(i, PC)]

    def ping(self):
        # TODO(d1): docstring
        return [i.ping() for i in self if isinstance(i, PC)]

class PCListsWidget(QtGui.QWidget):
    """A widget to display multiple PCLists side by side."""

    def __init__(self):
        """Construct a new PCListsWidget."""
        super().__init__()
        self.layout = QtGui.QHBoxLayout()
        self.setLayout(self.layout)

    def __iter__(self):
        # TODO(d1): docstring
        return iter(self.children())

    def addList(self, pclist):
        """Add a new PCList to the widget.

        Args:
            pclist (PCList): The new list
        """
        self.layout.addWidget(pclist)
        self.setLayout(self.layout)

class MainWindow(QtGui.QMainWindow):
    # TODO(d1): docstring
    def __init__(self):
        """Construct a new MainWindow"""
        super().__init__()
        self.PCButtonGroup = QtGui.QButtonGroup()
        self.executeable = ('','')

    def createLayout(self):
        # TODO(d1): docstring
        self.cwidget = QtGui.QWidget()
        self.clayout = QtGui.QVBoxLayout()
        self.setCentralWidget(self.cwidget)
        self.pclistswidget = PCListsWidget()
        self.clayout.addWidget(self.pclistswidget)
        self.clayout.addWidget(self.createControls())
        self.cwidget.setLayout(self.clayout)

    def createControls(self):
        # TODO(d1): docstring
        controlwidget = QtGui.QWidget()
        controllayout = QtGui.QGridLayout()
        controllayout.addWidget(self.pingButton(), 0, 0)
        controllayout.addWidget(self.wakeButton(), 0, 1)
        controllayout.addWidget(self.oTreeButton(), 0, 2)
        controllayout.addWidget(self.selectButton(), 1, 0)
        controllayout.addWidget(self.execButton(), 1, 1)
        controlwidget.setLayout(controllayout)
        return controlwidget

    def _button(self, name, func):
        button = QtGui.QPushButton(name)
        button.clicked.connect(func)
        return button

    def pingButton(self):
        return self._button('Ping', self.ping)

    def execButton(self):
        # TODO(d1): docstring
        return self._button('Execute',
                            partial(self.execCommand,
                                    command=self.executeable))

    def selectButton(self):
        # TODO(d1): docstring
        return self._button('Select executeable', self.commandSelector)

    def wakeButton(self):
        # TODO(d1): docstring
        return self._button('Wake up', self.wake)

    def oTreeButton(self):
        # TODO(d1): docstring
        return self._button('oTree', self.startOTree)

    def ping(self):
        return [i.ping() for i in self.pclistswidget if isinstance(i, PCList)]

    def execCommand(self, command):
        # TODO(d1): docstring
        return [i.execCommand(command) for i in self.pclistswidget
                if isinstance(i, PCList)]

    def wake(self):
        # TODO(d1): docstring
        return [i.wake() for i in self.pclistswidget if isinstance(i, PCList)]

    def commandSelector(self):
        # TODO(d1): docstring
        self.executeable = QtGui.QFileDialog.getOpenFileName(self, 'Find the executeable', '/', '')

    def startOTree(self):
        # TODO(d1): docstring
        self.execCommand(OTREE_EXEC__)

    def about(self):
        # TODO(d1): docstring
        QtGui.QMessageBox.about(self, 'AWIDominator', 'HILFEEEE')

if __name__ == "__main__":
    awidom = AWIDom()
    awidom.run()
    sys.exit(awidom.exec_())
<commit_msg>Icons now global<commit_after>import concurrent.futures
import copy
from enum import Enum
from functools import partial
import os
from platform import system as system_name
import PySide.QtCore as QtCore
from PySide.QtCore import QDir
from PySide.QtCore import QPoint
from PySide.QtCore import QSize
import PySide.QtGui as QtGui
import random
import sys
import threading
import yaml

# Configuration globals
CLIENTFILE__ = 'clients.yaml'
OTREE_EXEC__ = 'chrome.exe'
ORG__ = 'Alfred-Weber-Institut für Wirtschaftwissenschaften'
NAME__ = 'AWIDominator'
PSEXEC__ = '.\psexec.exe'
BROADCAST_IP__ = '255.255.255.255'

def sendWarning(text):
    # TODO(d1): docstring
    warnBox = QtGui.QMessageBox()
    warnBox.setWindowTitle('Warnung!')
    warnBox.setText(text)
    warnBox.setStandardButtons(QtGui.QMessageBox.Ok)
    return warnBox.exec_() == QtGui.QMessageBox.Ok

def sendBooleanQuery(text):
    # TODO(d1): docstring
    questionBox = QtGui.QMessageBox()
    questionBox.setWindowTitle('Achtung!')
    questionBox.setText(text)
    questionBox.setStandardButtons(QtGui.QMessageBox.Yes)
    questionBox.addButton(QtGui.QMessageBox.No)
    questionBox.setDefaultButton(QtGui.QMessageBox.No)
    return questionBox.exec_() == QtGui.QMessageBox.Yes

class Ternary(Enum):
    # TODO(d1): docstring
    OFF = 0
    ON = 1
    UNKNOWN = 2

# Runtime globals
class ICONS(object):
    # TODO(d1): docstring
    ON = 0
    OFF = 0
    UNKOWN = 0

class AWIDom(QtGui.QApplication):
    """Handles the whole program."""

    def __init__(self, cfile=CLIENTFILE__):
        """
        Consturct a AWIDOM

        Args:
            cfile (string, optional): The path to the configuration file.
        """
        super().__init__(sys.argv)
        self.setOrganizationName(ORG__)
        self.setApplicationName(NAME__)
        self.settings = QtCore.QSettings()
        self.left = PCList('Left side')
        self.right = PCList('Right side')
        self.otree_uri = ''
        self.loadIcons()
        self.loadConfig(cfile)
        self.createWindow()

    def loadConfig(self, cfile):
        """Loads a configuration file and fills the memebers accordingly.

        Args:
            cfile (string): The path to the configuration file
        """
        with open(cfile, 'r') as f:
            try:
                clientsconf = yaml.load(f)
                self.loadPCs(self.left, clientsconf['left'])
                self.loadPCs(self.right, clientsconf['right'])
                self.otree_uri = clientsconf['otree-uri']
            except yaml.YAMLError as e:
                print(e)
                sendWarning('Configuration couldn\'t be loaded')
                sys.exit()

    def loadPCs(self, target, confs):
        """Goes throgh a list of PCs from a conf file and appends them to a
        PCList.

        Args:
            target (PCList): A PCList to append the new PCs to.
            confs (list): A list of PCs in dict form
        """
        return [target.append(PC(c['id'], c['name'], c['ip'], c['mac']))
                for c in confs]

    def loadIcons(self):
        # TODO(d1): docstring
        pixmap_on = QtGui.QPixmap('./assets/font_awesome_toggle_on.png')
        pixmap_off = QtGui.QPixmap('./assets/font_awesome_toggle_off.png')
        pixmap_question = QtGui.QPixmap('./assets/font_awesome_question.png')
        ICONS.ON = QtGui.QIcon(pixmap_on)
        ICONS.OFF = QtGui.QIcon(pixmap_off)
        ICONS.QUESTION = QtGui.QIcon(pixmap_question)

    def createWindow(self):
        """Creates the window for the application without showing/displaying it.
        """
        self.mainwindow = MainWindow()
        self.mainwindow.createLayout()
        self.mainwindow.pclistswidget.addList(self.left)
        self.mainwindow.pclistswidget.addList(self.right)

    def run(self):
        """Showing the constructed window to the user."""
        self.mainwindow.show()

class PC(QtGui.QCheckBox):
    """Handles one PC in the lab"""

    def __init__(self, id, name, ip, mac):
        """Initalizes the PC

        Args:
            id (int): The id for this PC
            name (str): A string as identifier
            ip (str): The IPv4-address
            mac (str): the MAC-address of this PC
        """
        super().__init__(name)
        self.id = id
        self.name = name
        self.ip = ip
        self.setMac(mac)
        self.setOnline(Ternary.UNKNOWN)
        self.isPinging = False

    def __lt__(self, other):
        """Less then comparison operator

        Args:
            other (PC): The other PC
        Returns:
            self.id < other.id
        """
        return self.id < other.id

    def __repr__(self):
        """Representation of a PC"""
        return repr((self.id, self.name, self.ip, self.mac))

    def __str__(self):
        """Nice formatted string output for a PC"""
        return ('PC: [id: {}, name: {}, ip: {}, mac: {}]'
                ''.format(self.id, self.name, self.ip, self.mac))

    def setMac(self, mac):
        # TODO(d1): docstring
        if len(mac) == 12:
            pass
        elif len(mac) == 12 + 5:
            sep = mac[2]
            mac = mac.replace(sep, '')
        else:
            raise ValueError('Incorrect MAC address format')
        self.mac = mac

    def setOnline(self, status):
        # TODO(d1): docstring
        self.online = Ternary(status)
        self.setOnlineIcon()

    def setOnlineIcon(self):
        # TODO(d1): docstring
        if self.online == Ternary.ON:
            self.setIcon(ICONS.ON)
        elif self.online == Ternary.OFF:
            self.setIcon(ICONS.OFF)
        else:
            self.setIcon(ICONS.QUESTION)
        self.setIconSize(QtCore.QSize(16, 16))

    def _ping(self):
        """Ping this PC"""
        self.isPinging = True
        self.setOnline(Ternary.UNKNOWN)
        ping_param = '-n 1' if system_name().lower() == 'windows' else '-c 1'
        isOnline = os.system('ping {} {}'.format(ping_param, self.ip)) == 0
        if isOnline:
            self.setOnline(Ternary.ON)
        else:
            self.setOnline(Ternary.OFF)
        self.isPinging = False
        return isOnline

    def ping(self):
        # TODO(d1): docstring
        if not self.isPinging:
            ping_thread = threading.Thread(target=self._ping)
            ping_thread.start()

    def _wake(host):
        # TODO(d1): docstring
        # Pad the synchronization stream.
        data = ''.join(['FFFFFFFFFFFF', self.mac * 20])
        send_data = b''

        # Split up the hex values and pack.
        for i in range(0, len(data), 2):
            send_data = b''.join([send_data,
                                  struct.pack('B', int(data[i: i + 2], 16))])

        # Broadcast it to the LAN.
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.sendto(send_data, (BROADCAST_IP__, 7))
        return True

    def wake(self):
        # TODO(d1): docstring
        if not self.isChecked():
            return True
        if self.online != Ternary.ON:
            self._wake()
            self.setOnline(Ternary.UNKNOWN)
            # self.checked = False
        else:
            sendWarning('{} is already alive.'.format(self.name))

    def execCommand(self, command):
        # TODO(d1): docstring
        if not self.isChecked():
            return True
        if self.online == Ternary.ON:
            self.setChecked(False)
            print('Executing {} on {}'.format(command, self.name))
        else:
            sendWarning('{} is not alive.'.format(self.name))

class PCList(QtGui.QGroupBox):
    """A List of Buttons/Models of PCs, used to display as a list."""

    def __init__(self, title, pc_list=None):
        """Consturcts a new PCList.

        Args:
            title (str): The Title for the list, will be shown.
            pc_list (list, optional): The List of PCs added to the object.
        """
        super().__init__(title)
        self.layout = QtGui.QVBoxLayout()
        if pc_list is not None:
            self.load(pc_list)

    def __iter__(self):
        # TODO(d1): docstring
        return iter(self.children())

    def load(self, pc_list):
        """Append all PCs in a list to this PCList.

        Args:
            pc_list (list): A list of PCs.
        """
        return [self.append(pc) for pc in pc_list]

    def append(self, pc):
        """Append a single pc to the List:

        Args:
            pc (PC): The pc.
        """
        self.layout.addWidget(pc)
        pc.ping()
        self.setLayout(self.layout)

    def selectAll(self):
        # TODO(d1): docstring
        return [i.setChecked(True) for i in self if isinstance(i, PC)]

    def wake(self):
        # TODO(d1): docstring
        return [i.wake() for i in self if isinstance(i, PC)]

    def execCommand(self, command):
        # TODO(d1): docstring
        return [i.execCommand(command) for i in self if isinstance(i, PC)]

    def ping(self):
        # TODO(d1): docstring
        return [i.ping() for i in self if isinstance(i, PC) and i.isChecked()]

class PCListsWidget(QtGui.QWidget):
    """A widget to display multiple PCLists side by side."""

    def __init__(self):
        """Construct a new PCListsWidget."""
        super().__init__()
        self.createLayout()

    def __iter__(self):
        # TODO(d1): docstring
        return iter(self.children())

    def createLayout(self):
        # TODO(d1): docstring
        self.layout = QtGui.QVBoxLayout()
        self.listsLayout = QtGui.QHBoxLayout()
        self.controlsLayout = QtGui.QHBoxLayout()
        self.lists = QtGui.QWidget()
        self.controls = QtGui.QWidget()
        self.lists.setLayout(self.listsLayout)
        self.controls.setLayout(self.controlsLayout)
        self.layout.addWidget(self.lists)
        self.layout.addWidget(self.controls)
        self.setLayout(self.layout)

    def addList(self, pclist):
        """Add a new PCList to the widget.

        Args:
            pclist (PCList): The new list
        """
        selectAllButton = QtGui.QPushButton('Select all')
        selectAllButton.clicked.connect(pclist.selectAll)
        self.listsLayout.addWidget(pclist)
        self.controlsLayout.addWidget(selectAllButton)
        self.lists.setLayout(self.listsLayout)
        self.controls.setLayout(self.controlsLayout)

class MainWindow(QtGui.QMainWindow):
    # TODO(d1): docstring
    def __init__(self):
        """Construct a new MainWindow"""
        super().__init__()
        self.PCButtonGroup = QtGui.QButtonGroup()
        self.executeable = ('','')

    def createLayout(self):
        # TODO(d1): docstring
        self.cwidget = QtGui.QWidget()
        self.clayout = QtGui.QVBoxLayout()
        self.setCentralWidget(self.cwidget)
        self.pclistswidget = PCListsWidget()
        self.clayout.addWidget(self.pclistswidget)
        self.clayout.addWidget(self.createControls())
        self.cwidget.setLayout(self.clayout)

    def createControls(self):
        # TODO(d1): docstring
        controlwidget = QtGui.QWidget()
        controllayout = QtGui.QGridLayout()
        controllayout.addWidget(self._button('Ping',
                                             self.ping), 0, 0)
        controllayout.addWidget(self._button('Wake up',
                                             self.wake), 0, 1)
        controllayout.addWidget(self._button('oTree',
                                             self.startOTree), 0, 2)
        controllayout.addWidget(self._button('Select executeable',
                                             self.commandSelector), 1, 0)
        controllayout.addWidget(self.execButton(), 1, 1)
        controlwidget.setLayout(controllayout)
        return controlwidget

    def _button(self, name, func):
        # TODO(d1): docstring
        button = QtGui.QPushButton(name)
        button.clicked.connect(func)
        return button

    def execButton(self):
        # TODO(d1): docstring
        return self._button('Execute',
                            partial(self.execCommand,
                                    command=self.executeable))

    def ping(self):
        # TODO(d1): docstring
        return [i.ping() for i in self.pclistswidget if isinstance(i, PCList)]

    def execCommand(self, command):
        # TODO(d1): docstring
        return [i.execCommand(command) for i in self.pclistswidget
                if isinstance(i, PCList)]

    def wake(self):
        # TODO(d1): docstring
        return [i.wake() for i in self.pclistswidget if isinstance(i, PCList)]

    def commandSelector(self):
        # TODO(d1): docstring
        self.executeable = QtGui.QFileDialog.getOpenFileName(self, 'Find the executeable', '/', '')

    def startOTree(self):
        # TODO(d1): docstring
        self.execCommand(OTREE_EXEC__)

    def about(self):
        # TODO(d1): docstring
        QtGui.QMessageBox.about(self, 'AWIDominator', 'HILFEEEE')

if __name__ == "__main__":
    awidom = AWIDom()
    awidom.run()
    sys.exit(awidom.exec_())
<|endoftext|>