<commit_before>#!/usr/bin/env python

import urllib
import json
import os

from flask import Flask
from flask import request
from flask import make_response
import requests

# Flask app should start in global layout
app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print("Request:")
    print(json.dumps(req, indent=4))

    res = makeWebhookResult(req)

    res = json.dumps(res, indent=4)
    print(res)
    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'
    return r

def creatDraft(parameters):
    categories = {'jeans': "11483", 'camera': "31388"}
    condtions = {'new': "1000", 'used': "3000"}

    item = parameters.get("item")
    condtion = parameters.get("condtion")
    brand = parameters.get("brand")
    model = parameters.get("model")

    url = "http://1f0cb7bf.ngrok.io/experience/consumer_selling/v1/listing_draft/create_and_open?mode=AddItem"

    payload = {
        "requestListing": {
            "item": {
                "title": item
            },
            "categoryId": categories[item],
            "condition": "1000"
        }
    }

    headers = {
        'Authorization': "Bearer v^1.1#i^1#r^1#f^0#I^3#p^3#t^Ul4xMF8yOjBEMUVDODQxMTZBMzQ2QkNFQjM4MUE1MkEyNDREOEIxXzFfMSNFXjUxNg==",
        'X-EBAY-C-ENDUSERCTX': "deviceId=4fe2d65bc464493aa9babd91aa259027,userAgent=Mozilla%2F5.0+%28iPad%3B+CPU+OS+7_0+like+Mac+OS+X%29+AppleWebKit%2F537.51.1+%28KHTML%2C+like+Gecko%29+Version%2F7.0+Mobile%2F11A465+Safari%2F9537.53",
        'X-EBAY-C-MARKETPLACE-ID': "EBAY-US",
        'Content-Type': "application/json",
        'X-EBAY-C-TRACKING': "cguid=049205231500a62960f4f874f775d8e2595427bd,tguid=049229b01504050a19118a10011c1e36595427bd,pageid=2380506,guid=049229b01504050a19118a10011c1e36",
        'Accept': 'application/json'
    }

    response = requests.post(url, json=payload, headers=headers)
    if response.status_code == 200:
        responseJS = json.loads(response.content)
        return responseJS
    else:
        return response.status_code

def updateItem(draftId):

    url = "http://1f0cb7bf.ngrok.io/experience/consumer_selling/v1/listing_draft/" + str(draftId) + "?mode=AddItem"

    payload = {
        "requestListing": {
            "item": {
                "itemSpecific": [
                    {
                        "name": "Brand",
                        "value": [
                            "cannon"
                        ]
                    },
                    {
                        "name": "Model",
                        "value": [
                            "t6i"
                        ]
                    },
                    {
                        "name": "Series",
                        "value": [
                            "58mm"
                        ]
                    }
                ],
                "title": "camera",
                "picture": [
                    {
                      "url": "http://www.imaging-resource.com/PRODS/canon-t6i/Z-CANON-T6I-BEAUTY.JPG"
                    },
                    {
                      "url": "https://static.bhphotovideo.com/explora/sites/default/files/T6i_0.jpg"
                    },
                    {
                      "url": "http://bjselectronicsblog.com/wp-content/uploads/2016/02/Canon-Rebel-T6i-Best-Digital-SLR-Camera.jpg"
                    },
                    {
                      "url": "http://www.imaging-resource.com/PRODS/canon-t6i/Z-CANON-T6I-FRONTLEFT.JPG"
                    }
                  ],
                "description": "
add desc

"
            },
            "condition": "1000",
            "price": 20,
            "format": "Auction",
            "listingInfo": {
                "conditionDescription": "New with box",
                "description": "
add desc

"
            },
            "categoryId": "31388",
            "previousShippingType": "SHIP_RECO_0",
            "serviceContextMeta": "{\"restrictedRevise\":false,\"sellerSegment\":\"NEW\",\"recommendedStartPrice\":0.99,\"recommendedBinPrice\":3.99,\"format\":\"FixedPrice\",\"price\":3.99,\"featureQualifiedList\":\"2033,2034\"}"
        },
        "updatedModules": [
            "PHOTOS",
            "ASPECTS_MODULE",
            "CONDITION",
            "DESCRIPTION",
            "PRICE",
            "LISTINGINFO"
        ],
        "userInteractedModules": "ASPECTS_MODULE,PHOTOS,DESCRIPTION,PRICE"
    }

    headers = {
        'Authorization': "Bearer v^1.1#i^1#r^1#f^0#I^3#p^3#t^Ul4xMF8yOjBEMUVDODQxMTZBMzQ2QkNFQjM4MUE1MkEyNDREOEIxXzFfMSNFXjUxNg==",
        'X-EBAY-C-ENDUSERCTX': "deviceId=4fe2d65bc464493aa9babd91aa259027,userAgent=Mozilla%2F5.0+%28iPad%3B+CPU+OS+7_0+like+Mac+OS+X%29+AppleWebKit%2F537.51.1+%28KHTML%2C+like+Gecko%29+Version%2F7.0+Mobile%2F11A465+Safari%2F9537.53",
        'X-EBAY-C-MARKETPLACE-ID': "EBAY-US",
        'Content-Type': "application/json"
    }

    response = requests.put(url, json=payload, headers=headers)
    responseJS = json.loads(response.content)

    return responseJS

def publishItem(draftId):

    url = "http://1f0cb7bf.ngrok.io/experience/consumer_selling/v1/listing_draft/" + str(draftId) + "/publish?mode=AddItem"

    payload = {
        "requestListing": {
            "item": {
                "title": "camera"
            },
            "paymentInfo": {
                "paypalEmailAddress": "ebaysellbot@gmail.com"
            },
            "categoryId": "31388",
            "condition": "1000",
            "format": "Auction",
            "itemLocation": {
                "zipCode": "95134"
            },
            "priceBundle": "bestChanceToSell",
            "startPrice": 17.96,
            "previousShippingType": "SHIP_RECO_0"
        },
        "customInfo": {
            "descriptionEditor": "standard",
            "zipCode": "95134",
            "priceBundle": "bestChanceToSell",
            "startPrice": "17.96",
            "previousShippingType": "SHIP_RECO_0"
        }
    }

    headers = {
        'Authorization': "Bearer v^1.1#i^1#r^1#f^0#I^3#p^3#t^Ul4xMF8yOjBEMUVDODQxMTZBMzQ2QkNFQjM4MUE1MkEyNDREOEIxXzFfMSNFXjUxNg==",
        'X-EBAY-C-ENDUSERCTX': "deviceId=4fe2d65bc464493aa9babd91aa259027,userAgent=Mozilla%2F5.0+%28iPad%3B+CPU+OS+7_0+like+Mac+OS+X%29+AppleWebKit%2F537.51.1+%28KHTML%2C+like+Gecko%29+Version%2F7.0+Mobile%2F11A465+Safari%2F9537.53",
        'X-EBAY-C-MARKETPLACE-ID': "EBAY-US",
        'Content-Type': "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)
    responseJS = json.loads(response.content)

    return responseJS

def makeWebhookResult(req):
    result = req.get("result")
    parameters = result.get("parameters")
    item = parameters.get("item")

    if req.get("result").get("action") == "item.create":
        responseJS = creatDraft(parameters)
        draftId = responseJS["modules"]['SELL_NODE_CTA']['paramList']['draftId']
        startPrice = responseJS["modules"]['PRICE']['bestChanceToSell']['price']['value']
        with open('data.json', 'w') as f:
            json.dump({"latestDraftId": draftId}, f)
        speech = 'Sure, I can help you sell your ' + item + ' on eBay with draftId as displayed. According to similar sold items, ' \
                 'It will list with 7 day auction with starting price of $' + startPrice + '. Can I publish for you?'
        text = 'Sure, I can help you sell your ' + item + ' on eBay with draftId ' + str(draftId) + '. According to similar sold items, ' \
                 'It will list with 7 day auction with starting price of $' + startPrice + '. Can I publish for you?'
    elif req.get("result").get("action") == "item.publish":
        with open('data.json') as f:
            data = json.load(f)
        draftId = data["latestDraftId"]
        updateItemResponse = updateItem(draftId)
        speech = 'status code' + updateItemResponse["modules"]['SELL_NODE_CTA']['paramList']['draftId']
        text = speech
    else:
        return {}

    print("Response:")
    print(speech)
    print(text)

    return {
        "speech": speech,
        "displayText": text,
        #"data": {},
        # "contextOut": [],
        "source": "apiai-onlinestore-shipping"
    }

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print ("Starting app on port %d" % port)

    app.run(debug=True, port=port, host='0.0.0.0')

<commit_msg>test draft id<commit_after>#!/usr/bin/env python

import urllib
import json
import os

from flask import Flask
from flask import request
from flask import make_response
import requests

# Flask app should start in global layout
app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)

    print("Request:")
    print(json.dumps(req, indent=4))

    res = makeWebhookResult(req)

    res = json.dumps(res, indent=4)
    print(res)
    r = make_response(res)
    r.headers['Content-Type'] = 'application/json'
    return r

def creatDraft(parameters):
    categories = {'jeans': "11483", 'camera': "31388"}
    condtions = {'new': "1000", 'used': "3000"}

    item = parameters.get("item")
    condtion = parameters.get("condtion")
    brand = parameters.get("brand")
    model = parameters.get("model")

    url = "http://1f0cb7bf.ngrok.io/experience/consumer_selling/v1/listing_draft/create_and_open?mode=AddItem"

    payload = {
        "requestListing": {
            "item": {
                "title": item
            },
            "categoryId": categories[item],
            "condition": "1000"
        }
    }

    headers = {
        'Authorization': "Bearer v^1.1#i^1#r^1#f^0#I^3#p^3#t^Ul4xMF8yOjBEMUVDODQxMTZBMzQ2QkNFQjM4MUE1MkEyNDREOEIxXzFfMSNFXjUxNg==",
        'X-EBAY-C-ENDUSERCTX': "deviceId=4fe2d65bc464493aa9babd91aa259027,userAgent=Mozilla%2F5.0+%28iPad%3B+CPU+OS+7_0+like+Mac+OS+X%29+AppleWebKit%2F537.51.1+%28KHTML%2C+like+Gecko%29+Version%2F7.0+Mobile%2F11A465+Safari%2F9537.53",
        'X-EBAY-C-MARKETPLACE-ID': "EBAY-US",
        'Content-Type': "application/json",
        'X-EBAY-C-TRACKING': "cguid=049205231500a62960f4f874f775d8e2595427bd,tguid=049229b01504050a19118a10011c1e36595427bd,pageid=2380506,guid=049229b01504050a19118a10011c1e36",
        'Accept': 'application/json'
    }

    response = requests.post(url, json=payload, headers=headers)
    if response.status_code == 200:
        responseJS = json.loads(response.content)
        return responseJS
    else:
        return response.status_code

def updateItem(draftId):

    url = "http://1f0cb7bf.ngrok.io/experience/consumer_selling/v1/listing_draft/" + str(draftId) + "?mode=AddItem"

    payload = {
        "requestListing": {
            "item": {
                "itemSpecific": [
                    {
                        "name": "Brand",
                        "value": [
                            "cannon"
                        ]
                    },
                    {
                        "name": "Model",
                        "value": [
                            "t6i"
                        ]
                    },
                    {
                        "name": "Series",
                        "value": [
                            "58mm"
                        ]
                    }
                ],
                "title": "camera",
                "picture": [
                    {
                      "url": "http://www.imaging-resource.com/PRODS/canon-t6i/Z-CANON-T6I-BEAUTY.JPG"
                    },
                    {
                      "url": "https://static.bhphotovideo.com/explora/sites/default/files/T6i_0.jpg"
                    },
                    {
                      "url": "http://bjselectronicsblog.com/wp-content/uploads/2016/02/Canon-Rebel-T6i-Best-Digital-SLR-Camera.jpg"
                    },
                    {
                      "url": "http://www.imaging-resource.com/PRODS/canon-t6i/Z-CANON-T6I-FRONTLEFT.JPG"
                    }
                  ],
                "description": "
add desc

"
            },
            "condition": "1000",
            "price": 20,
            "format": "Auction",
            "listingInfo": {
                "conditionDescription": "New with box",
                "description": "
add desc

"
            },
            "categoryId": "31388",
            "previousShippingType": "SHIP_RECO_0",
            "serviceContextMeta": "{\"restrictedRevise\":false,\"sellerSegment\":\"NEW\",\"recommendedStartPrice\":0.99,\"recommendedBinPrice\":3.99,\"format\":\"FixedPrice\",\"price\":3.99,\"featureQualifiedList\":\"2033,2034\"}"
        },
        "updatedModules": [
            "PHOTOS",
            "ASPECTS_MODULE",
            "CONDITION",
            "DESCRIPTION",
            "PRICE",
            "LISTINGINFO"
        ],
        "userInteractedModules": "ASPECTS_MODULE,PHOTOS,DESCRIPTION,PRICE"
    }

    headers = {
        'Authorization': "Bearer v^1.1#i^1#r^1#f^0#I^3#p^3#t^Ul4xMF8yOjBEMUVDODQxMTZBMzQ2QkNFQjM4MUE1MkEyNDREOEIxXzFfMSNFXjUxNg==",
        'X-EBAY-C-ENDUSERCTX': "deviceId=4fe2d65bc464493aa9babd91aa259027,userAgent=Mozilla%2F5.0+%28iPad%3B+CPU+OS+7_0+like+Mac+OS+X%29+AppleWebKit%2F537.51.1+%28KHTML%2C+like+Gecko%29+Version%2F7.0+Mobile%2F11A465+Safari%2F9537.53",
        'X-EBAY-C-MARKETPLACE-ID': "EBAY-US",
        'Content-Type': "application/json"
    }

    response = requests.put(url, json=payload, headers=headers)
    responseJS = json.loads(response.content)

    return responseJS

def publishItem(draftId):

    url = "http://1f0cb7bf.ngrok.io/experience/consumer_selling/v1/listing_draft/" + str(draftId) + "/publish?mode=AddItem"

    payload = {
        "requestListing": {
            "item": {
                "title": "camera"
            },
            "paymentInfo": {
                "paypalEmailAddress": "ebaysellbot@gmail.com"
            },
            "categoryId": "31388",
            "condition": "1000",
            "format": "Auction",
            "itemLocation": {
                "zipCode": "95134"
            },
            "priceBundle": "bestChanceToSell",
            "startPrice": 17.96,
            "previousShippingType": "SHIP_RECO_0"
        },
        "customInfo": {
            "descriptionEditor": "standard",
            "zipCode": "95134",
            "priceBundle": "bestChanceToSell",
            "startPrice": "17.96",
            "previousShippingType": "SHIP_RECO_0"
        }
    }

    headers = {
        'Authorization': "Bearer v^1.1#i^1#r^1#f^0#I^3#p^3#t^Ul4xMF8yOjBEMUVDODQxMTZBMzQ2QkNFQjM4MUE1MkEyNDREOEIxXzFfMSNFXjUxNg==",
        'X-EBAY-C-ENDUSERCTX': "deviceId=4fe2d65bc464493aa9babd91aa259027,userAgent=Mozilla%2F5.0+%28iPad%3B+CPU+OS+7_0+like+Mac+OS+X%29+AppleWebKit%2F537.51.1+%28KHTML%2C+like+Gecko%29+Version%2F7.0+Mobile%2F11A465+Safari%2F9537.53",
        'X-EBAY-C-MARKETPLACE-ID': "EBAY-US",
        'Content-Type': "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)
    responseJS = json.loads(response.content)

    return responseJS

def makeWebhookResult(req):
    result = req.get("result")
    parameters = result.get("parameters")
    item = parameters.get("item")

    if req.get("result").get("action") == "item.create":
        responseJS = creatDraft(parameters)
        draftId = responseJS["modules"]['SELL_NODE_CTA']['paramList']['draftId']
        startPrice = responseJS["modules"]['PRICE']['bestChanceToSell']['price']['value']
        with open('data.json', 'w') as f:
            json.dump({"latestDraftId": draftId}, f)
        speech = 'Sure, I can help you sell your ' + item + ' on eBay with draftId as displayed. According to similar sold items, ' \
                 'It will list with 7 day auction with starting price of $' + startPrice + '. Can I publish for you?'
        text = 'Sure, I can help you sell your ' + item + ' on eBay with draftId ' + str(draftId) + '. According to similar sold items, ' \
                 'It will list with 7 day auction with starting price of $' + startPrice + '. Can I publish for you?'
    elif req.get("result").get("action") == "item.publish":
        with open('data.json') as f:
            data = json.load(f)
        draftId = data["latestDraftId"]
        updateItemResponse = updateItem(draftId)
        speech = 'create draft id' + draftId + 'update status code' + updateItemResponse['meta']['requestParameters']['draftId']
        text = speech
    else:
        return {}

    print("Response:")
    print(speech)
    print(text)

    return {
        "speech": speech,
        "displayText": text,
        #"data": {},
        # "contextOut": [],
        "source": "apiai-onlinestore-shipping"
    }

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print ("Starting app on port %d" % port)

    app.run(debug=True, port=port, host='0.0.0.0')

<|endoftext|>


<commit_before>from devilry.utils import OrderedDict
from devilry.apps.core.models import AssignmentGroup

class GroupList(list):
    """
    Represents a list of :class:`devilry.apps.core.models.AssignmentGroup` objects,
    with utility functions for commonly needed actions. The list is ment to hold
    groups where the same student in candidate on a single assignment, and the
    utilities is ment to make it easier to work with the added complexity of
    supporting the same user in multiple groups on a single assignment.
    """
    def get_feedback_with_most_points(self):
        """
        Get the :class:`devilry.apps.core.models.StaticFeedback` with the most points in the list.
        """
        best = None
        for group in self:
            if best:
                if group.feedback and group.feedback.points > best.points:
                    best = group
            else:
                best = group.feedback
        return best

    def get_best_gradestring(self):
        """
        Uses :meth:`.get_feedback_with_most_points` to get the feedback with most points,
        and returns the ``grade``-attribute of that feedaback.

        :return: The grade or ``None``.
        """
        best = self.get_feedback_with_most_points()
        if best:
            return best.grade
        else:
            return None

    def _serialize_feedback(self, feedback):
        if feedback:
            return {'id': feedback.id,
                    'grade': feedback.grade,
                    'points': feedback.points,
                    'is_passing_grade': feedback.is_passing_grade,
                    'save_timestamp': feedback.save_timestamp}
        else:
            return None

    def serialize(self):
        out = {
            'feedbacks': [self._serialize_feedback(group.feedback) for group in self]
        }
        return out

class AggreatedRelatedStudentInfo(object):
    """
    Used by :class:`.GroupsGroupedByRelatedStudentAndAssignment` to stores all results for a
    single student on a period.
    """
    def __init__(self, user, assignments, relatedstudent=None):
        #: The Django user object for the student.
        self.user = user

        #: Dict of assignments where the key is the assignment-id, and the value is a :class:`.GroupList`.
        self.assignments = assignments

        #: The :class:`devilry.apps.core.models.RelatedStudent` for users that are related students.
        #: This is only available for the objects returned by
        #: :meth:`.GroupsGroupedByRelatedStudentAndAssignment.iter_relatedstudents_with_results`,
        #: and not for the objects returned by the ignored students iterators.
        self.relatedstudent = relatedstudent

    def iter_groups_by_assignment(self):
        """
        Returns an iterator over all :class:`.GroupList` objects for this student.
        Shortcut for ``self.assignments.itervalues()``.
        """
        return self.assignments.itervalues()

    def add_group(self, group):
        """
        Used by :class:`.GroupsGroupedByRelatedStudentAndAssignment` to add groups.
        """
        self.assignments[group.parentnode_id].append(group)

    def prettyprint(self):
        """
        Prettyprint for debugging.
        """
        print '{0}:'.format(self.user)
        for assignmentid, groups in self.assignments.iteritems():
            print '  - Assignment ID: {0}'.format(assignmentid)
            for group in groups:
                if group.feedback:
                    grade = '{0} (points:{1},passed:{2})'.format(group.feedback.grade,
                        group.feedback.points, group.feedback.is_passing_grade)
                else:
                    grade = None
                print '    - {0}: {1}'.format(group, grade)

    def __str__(self):
        """
        Returns a short representation of the object that should be useful when debugging.
        """
        return u'AggreatedRelatedStudentInfo(user={0}, assignmentcount={1}, grades={2!r})'.format(
            self.user.username,
            len(self.assignments),
            [str(gradelist.get_best_gradestring()) for gradelist in self.iter_groups_by_assignment()]
        )

    def _serialize_user(self, user):
        return {'id': user.id,
                'username': user.username,
                'email': user.email,
                'full_name': user.devilryuserprofile.full_name}

    def serialize(self):
        out = {'id': self.user.id, # NOTE: This is added to support stupid datamodel layers, like ExtJS, which does not support the ID of a record to be within an attribute
               'user': self._serialize_user(self.user),
               'groups_by_assignment': [],
               'relatedstudent': None}
        if self.relatedstudent:
            out['relatedstudent'] = {
                'id': self.relatedstudent.id,
                'tags': self.relatedstudent.tags,
                'candidate_id': self.relatedstudent.candidate_id}
        for assignmentid, grouplist in self.assignments.iteritems():
            out['groups_by_assignment'].append({'assignmentid': assignmentid,
                                                'grouplist': grouplist.serialize()})
        return out

class GroupsGroupedByRelatedStudentAndAssignment(object):
    """
    Provides an easy-to-use API for overviews over the results of all students
    in a period.
    """
    def __init__(self, period):
        """
        :param period: A :class:`devilry.apps.core.models.Period` object.
        """
        self.period = period
        self._collect_assignments()
        self._initialize_result()
        self._add_groups_to_result()

    def get_assignment_queryset(self):
        """
        Get the queryset used to fetch all assignments on the period.
        Override for custom ordering or if you need to optimize the query for
        your usecase (``select_related``, ``prefetch_related``, etc.)
        """
        return self.period.assignments.all().order_by('publishing_time')

    def get_relatedstudents_queryset(self):
        """
        Get the queryset used to fetch all relatedstudents on the period.
        Override if you need to optimize the query for your usecase
        (``select_related``, ``prefetch_related``, etc.)
        """
        return self.period.relatedstudent_set.all().select_related('user', 'user__devilryuserprofile')

    def get_groups_queryset(self):
        """
        Get the queryset used to fetch all groups on the period.
        Override if you need to optimize the query for your usecase
        (``select_related``, ``prefetch_related``, etc.)
        """
        groupqry = AssignmentGroup.objects.filter(parentnode__parentnode=self.period)
        groupqry = groupqry.select_related('parentnode', 'parentnode__parentnode', 'feedback')
        groupqry = groupqry.prefetch_related('candidates', 'candidates__student',
            'candidates__student__devilryuserprofile')
        return groupqry

    def _collect_assignments(self):
        self.assignments = []
        for assignment in self.get_assignment_queryset():
            self.assignments.append(assignment)

    def _create_assignmentsdict(self):
        dct = OrderedDict()
        for assignment in self.assignments:
            dct[assignment.id] = GroupList()
        return dct

    def _initialize_result(self):
        self.result = {}
        for relatedstudent in self.get_relatedstudents_queryset():
            self.result[relatedstudent.user_id] = AggreatedRelatedStudentInfo(
                user = relatedstudent.user,
                assignments = self._create_assignmentsdict(),
                relatedstudent=relatedstudent
            )

    def _create_or_add_ignoredgroup(self, ignoreddict, candidate):
        if not candidate.student_id in ignoreddict:
            ignoreddict[candidate.student_id] = AggreatedRelatedStudentInfo(
                user = candidate.student,
                assignments = self._create_assignmentsdict()
            )
        return ignoreddict[candidate.student_id]

    def _add_groups_to_result(self):
        groupqry = self.get_groups_queryset()
        self.ignored_students = {}
        self.ignored_students_with_results = {}
        for group in groupqry:
            for candidate in group.candidates.all():
                if candidate.student_id in self.result:
                    self.result[candidate.student_id].add_group(group)
                else:
                    self._create_or_add_ignoredgroup(self.ignored_students, candidate).add_group(group)
                    if group.feedback:
                        self._create_or_add_ignoredgroup(self.ignored_students_with_results, candidate).add_group(group)

    def iter_assignments(self):
        """
        Iterate over all the assignments, yielding Assignment-objects. The objects
        are iterated in the order returned by :meth:`get_assignment_queryset`.
        """
        return self.assignments.__iter__()

    def iter_relatedstudents_with_results(self):
        """
        Iterate over all relatedstudents, yielding a dict with the following attributes for each
        related student:

            user
                The Django user-object for the student.
            assignments
                An OrderedDict, ordered the same as :meth:`.iter_assignments`, where the key is
                the assignment-id, and the value is a list of AssignmentGroup-objects where the user
                is candidate. The list may have 0 or more groups, 0 if the user is not in any group
                on the assignment, and more than 1 if the user is in more than one group on the
                assignment.
        """
        return self.result.itervalues()

    def iter_students_that_is_candidate_but_not_in_related(self):
        """
        Iterate over the students that is candidate on one or more groups, but not registered as
        related students.
        """
        return self.ignored_students.itervalues()

    def iter_students_with_feedback_that_is_candidate_but_not_in_related(self):
        """
        Same as :meth:`.iter_students_that_is_candidate_but_not_in_related`, but it does not include
        the students that have no feedback.
        """
        return self.ignored_students_with_results.itervalues()

    def _serialize_assignment(self, basenode):
        return {'id': basenode.id,
                'short_name': basenode.short_name,
                'long_name': basenode.long_name}

    def serialize(self):
        """
        Serialize all the collected data as plain python objects.
        """
        out = {
            'relatedstudents':
                [r.serialize() for r in self.iter_relatedstudents_with_results()],
            'students_that_is_candidate_but_not_in_related':
                [r.serialize() for r in self.iter_students_that_is_candidate_but_not_in_related()],
            'students_with_feedback_that_is_candidate_but_not_in_related':
                [r.serialize() for r in self.iter_students_with_feedback_that_is_candidate_but_not_in_related()],
            'assignments':
                [self._serialize_assignment(a) for a in self.iter_assignments()]
        }
        return out<commit_msg>devilry.utils.groups_groupedby_relatedstudent_and_assignment: More group info in serialized output.<commit_after>from devilry.utils import OrderedDict
from devilry.apps.core.models import AssignmentGroup

class GroupList(list):
    """
    Represents a list of :class:`devilry.apps.core.models.AssignmentGroup` objects,
    with utility functions for commonly needed actions. The list is ment to hold
    groups where the same student in candidate on a single assignment, and the
    utilities is ment to make it easier to work with the added complexity of
    supporting the same user in multiple groups on a single assignment.
    """
    def get_feedback_with_most_points(self):
        """
        Get the :class:`devilry.apps.core.models.StaticFeedback` with the most points in the list.
        """
        best = None
        for group in self:
            if best:
                if group.feedback and group.feedback.points > best.points:
                    best = group
            else:
                best = group.feedback
        return best

    def get_best_gradestring(self):
        """
        Uses :meth:`.get_feedback_with_most_points` to get the feedback with most points,
        and returns the ``grade``-attribute of that feedaback.

        :return: The grade or ``None``.
        """
        best = self.get_feedback_with_most_points()
        if best:
            return best.grade
        else:
            return None

    def _serialize_feedback(self, feedback):
        if feedback:
            return {'id': feedback.id,
                    'grade': feedback.grade,
                    'points': feedback.points,
                    'is_passing_grade': feedback.is_passing_grade,
                    'save_timestamp': feedback.save_timestamp}
        else:
            return None

    def _serialize_group(self, group):
        return {
            'id': group.id,
            'feedback': self._serialize_feedback(group.feedback),
            'status': group.get_status()
        }

    def serialize(self):
        return [self._serialize_group(group) for group in self]

class AggreatedRelatedStudentInfo(object):
    """
    Used by :class:`.GroupsGroupedByRelatedStudentAndAssignment` to stores all results for a
    single student on a period.
    """
    def __init__(self, user, assignments, relatedstudent=None):
        #: The Django user object for the student.
        self.user = user

        #: Dict of assignments where the key is the assignment-id, and the value is a :class:`.GroupList`.
        self.assignments = assignments

        #: The :class:`devilry.apps.core.models.RelatedStudent` for users that are related students.
        #: This is only available for the objects returned by
        #: :meth:`.GroupsGroupedByRelatedStudentAndAssignment.iter_relatedstudents_with_results`,
        #: and not for the objects returned by the ignored students iterators.
        self.relatedstudent = relatedstudent

    def iter_groups_by_assignment(self):
        """
        Returns an iterator over all :class:`.GroupList` objects for this student.
        Shortcut for ``self.assignments.itervalues()``.
        """
        return self.assignments.itervalues()

    def add_group(self, group):
        """
        Used by :class:`.GroupsGroupedByRelatedStudentAndAssignment` to add groups.
        """
        self.assignments[group.parentnode_id].append(group)

    def prettyprint(self):
        """
        Prettyprint for debugging.
        """
        print '{0}:'.format(self.user)
        for assignmentid, groups in self.assignments.iteritems():
            print '  - Assignment ID: {0}'.format(assignmentid)
            for group in groups:
                if group.feedback:
                    grade = '{0} (points:{1},passed:{2})'.format(group.feedback.grade,
                        group.feedback.points, group.feedback.is_passing_grade)
                else:
                    grade = None
                print '    - {0}: {1}'.format(group, grade)

    def __str__(self):
        """
        Returns a short representation of the object that should be useful when debugging.
        """
        return u'AggreatedRelatedStudentInfo(user={0}, assignmentcount={1}, grades={2!r})'.format(
            self.user.username,
            len(self.assignments),
            [str(gradelist.get_best_gradestring()) for gradelist in self.iter_groups_by_assignment()]
        )

    def _serialize_user(self, user):
        return {'id': user.id,
                'username': user.username,
                'email': user.email,
                'full_name': user.devilryuserprofile.full_name}

    def serialize(self):
        out = {'id': self.user.id, # NOTE: This is added to support stupid datamodel layers, like ExtJS, which does not support the ID of a record to be within an attribute
               'user': self._serialize_user(self.user),
               'groups_by_assignment': [],
               'relatedstudent': None}
        if self.relatedstudent:
            out['relatedstudent'] = {
                'id': self.relatedstudent.id,
                'tags': self.relatedstudent.tags,
                'candidate_id': self.relatedstudent.candidate_id}
        for assignmentid, grouplist in self.assignments.iteritems():
            out['groups_by_assignment'].append({'assignmentid': assignmentid,
                                                'grouplist': grouplist.serialize()})
        return out

class GroupsGroupedByRelatedStudentAndAssignment(object):
    """
    Provides an easy-to-use API for overviews over the results of all students
    in a period.
    """
    def __init__(self, period):
        """
        :param period: A :class:`devilry.apps.core.models.Period` object.
        """
        self.period = period
        self._collect_assignments()
        self._initialize_result()
        self._add_groups_to_result()

    def get_assignment_queryset(self):
        """
        Get the queryset used to fetch all assignments on the period.
        Override for custom ordering or if you need to optimize the query for
        your usecase (``select_related``, ``prefetch_related``, etc.)
        """
        return self.period.assignments.all().order_by('publishing_time')

    def get_relatedstudents_queryset(self):
        """
        Get the queryset used to fetch all relatedstudents on the period.
        Override if you need to optimize the query for your usecase
        (``select_related``, ``prefetch_related``, etc.)
        """
        return self.period.relatedstudent_set.all().select_related('user', 'user__devilryuserprofile')

    def get_groups_queryset(self):
        """
        Get the queryset used to fetch all groups on the period.
        Override if you need to optimize the query for your usecase
        (``select_related``, ``prefetch_related``, etc.)
        """
        groupqry = AssignmentGroup.objects.filter(parentnode__parentnode=self.period)
        groupqry = groupqry.select_related('parentnode', 'parentnode__parentnode', 'feedback')
        groupqry = groupqry.prefetch_related('candidates', 'candidates__student',
            'candidates__student__devilryuserprofile')
        return groupqry

    def _collect_assignments(self):
        self.assignments = []
        for assignment in self.get_assignment_queryset():
            self.assignments.append(assignment)

    def _create_assignmentsdict(self):
        dct = OrderedDict()
        for assignment in self.assignments:
            dct[assignment.id] = GroupList()
        return dct

    def _initialize_result(self):
        self.result = {}
        for relatedstudent in self.get_relatedstudents_queryset():
            self.result[relatedstudent.user_id] = AggreatedRelatedStudentInfo(
                user = relatedstudent.user,
                assignments = self._create_assignmentsdict(),
                relatedstudent=relatedstudent
            )

    def _create_or_add_ignoredgroup(self, ignoreddict, candidate):
        if not candidate.student_id in ignoreddict:
            ignoreddict[candidate.student_id] = AggreatedRelatedStudentInfo(
                user = candidate.student,
                assignments = self._create_assignmentsdict()
            )
        return ignoreddict[candidate.student_id]

    def _add_groups_to_result(self):
        groupqry = self.get_groups_queryset()
        self.ignored_students = {}
        self.ignored_students_with_results = {}
        for group in groupqry:
            for candidate in group.candidates.all():
                if candidate.student_id in self.result:
                    self.result[candidate.student_id].add_group(group)
                else:
                    self._create_or_add_ignoredgroup(self.ignored_students, candidate).add_group(group)
                    if group.feedback:
                        self._create_or_add_ignoredgroup(self.ignored_students_with_results, candidate).add_group(group)

    def iter_assignments(self):
        """
        Iterate over all the assignments, yielding Assignment-objects. The objects
        are iterated in the order returned by :meth:`get_assignment_queryset`.
        """
        return self.assignments.__iter__()

    def iter_relatedstudents_with_results(self):
        """
        Iterate over all relatedstudents, yielding a dict with the following attributes for each
        related student:

            user
                The Django user-object for the student.
            assignments
                An OrderedDict, ordered the same as :meth:`.iter_assignments`, where the key is
                the assignment-id, and the value is a list of AssignmentGroup-objects where the user
                is candidate. The list may have 0 or more groups, 0 if the user is not in any group
                on the assignment, and more than 1 if the user is in more than one group on the
                assignment.
        """
        return self.result.itervalues()

    def iter_students_that_is_candidate_but_not_in_related(self):
        """
        Iterate over the students that is candidate on one or more groups, but not registered as
        related students.
        """
        return self.ignored_students.itervalues()

    def iter_students_with_feedback_that_is_candidate_but_not_in_related(self):
        """
        Same as :meth:`.iter_students_that_is_candidate_but_not_in_related`, but it does not include
        the students that have no feedback.
        """
        return self.ignored_students_with_results.itervalues()

    def _serialize_assignment(self, basenode):
        return {'id': basenode.id,
                'short_name': basenode.short_name,
                'long_name': basenode.long_name}

    def serialize(self):
        """
        Serialize all the collected data as plain python objects.
        """
        out = {
            'relatedstudents':
                [r.serialize() for r in self.iter_relatedstudents_with_results()],
            'students_that_is_candidate_but_not_in_related':
                [r.serialize() for r in self.iter_students_that_is_candidate_but_not_in_related()],
            'students_with_feedback_that_is_candidate_but_not_in_related':
                [r.serialize() for r in self.iter_students_with_feedback_that_is_candidate_but_not_in_related()],
            'assignments':
                [self._serialize_assignment(a) for a in self.iter_assignments()]
        }
        return out<|endoftext|>


<commit_before>#  Copyright 2008-2009 Nokia Siemens Networks Oyj
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

from robot.variables import GLOBAL_VARIABLES

class ExecutionContext(object):

    def __init__(self, namespace, output, dry_run=False):
        self.namespace = namespace
        self.output = output
        self.dry_run = dry_run
        self.continue_on_failure = False

    def get_current_vars(self):
        return self.namespace.variables

    def end_test(self, test):
        self.output.end_test(test)
        self.namespace.end_test()
        self.continue_on_failure = False

    def end_suite(self, suite):
        self.output.end_suite(suite)
        self.namespace.end_suite()

    def output_file_changed(self, filename):
        self._set_global_variable('${OUTPUT_FILE}', filename)

    def replace_vars_from_setting(self, name, value, errors):
        return self.namespace.variables.replace_meta(name, value, errors)

    def log_file_changed(self, filename):
        self._set_global_variable('${LOG_FILE}', filename)

    def set_prev_test_variables(self, test):
        self._set_prev_test_variables(self.get_current_vars(), test.name,
                                      test.status, test.message)

    def copy_prev_test_vars_to_global(self):
        varz = self.get_current_vars()
        name, status, message = varz['${PREV_TEST_NAME}'], \
                    varz['${PREV_TEST_STATUS}'], varz['${PREV_TEST_MESSAGE}']
        self._set_prev_test_variables(GLOBAL_VARIABLES, name, status, message)

    def _set_prev_test_variables(self, destination, name, status, message):
        destination['${PREV_TEST_NAME}'] = name
        destination['${PREV_TEST_STATUS}'] = status
        destination['${PREV_TEST_MESSAGE}'] = message

    def _set_global_variable(self, name, value):
        self.namespace.variables.set_global(name, value)

    def report_suite_status(self, status, message):
        self.get_current_vars()['${SUITE_STATUS}'] = status
        self.get_current_vars()['${SUITE_MESSAGE}'] = message

    def start_test(self, test, continue_on_failure=False):
        self.continue_on_failure = continue_on_failure
        self.namespace.start_test(test)
        self.output.start_test(test)

    def set_test_status_before_teardown(self, message, status):
        self.namespace.set_test_status_before_teardown(message, status)

    def get_handler(self, name):
        return self.namespace.get_handler(name)

    def start_keyword(self, keyword):
        self.output.start_keyword(keyword)

    def end_keyword(self, keyword):
        self.output.end_keyword(keyword)

    def warn(self, message):
        self.output.warn(message)

    def trace(self, message):
        self.output.trace(message)
<commit_msg>Clean-up<commit_after>#  Copyright 2008-2009 Nokia Siemens Networks Oyj
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

from robot.variables import GLOBAL_VARIABLES

class ExecutionContext(object):

    def __init__(self, namespace, output, dry_run=False):
        self.namespace = namespace
        self.output = output
        self.dry_run = dry_run

    def get_current_vars(self):
        return self.namespace.variables

    def end_test(self, test):
        self.output.end_test(test)
        self.namespace.end_test()

    def end_suite(self, suite):
        self.output.end_suite(suite)
        self.namespace.end_suite()

    def output_file_changed(self, filename):
        self._set_global_variable('${OUTPUT_FILE}', filename)

    def replace_vars_from_setting(self, name, value, errors):
        return self.namespace.variables.replace_meta(name, value, errors)

    def log_file_changed(self, filename):
        self._set_global_variable('${LOG_FILE}', filename)

    def set_prev_test_variables(self, test):
        self._set_prev_test_variables(self.get_current_vars(), test.name,
                                      test.status, test.message)

    def copy_prev_test_vars_to_global(self):
        varz = self.get_current_vars()
        name, status, message = varz['${PREV_TEST_NAME}'], \
                    varz['${PREV_TEST_STATUS}'], varz['${PREV_TEST_MESSAGE}']
        self._set_prev_test_variables(GLOBAL_VARIABLES, name, status, message)

    def _set_prev_test_variables(self, destination, name, status, message):
        destination['${PREV_TEST_NAME}'] = name
        destination['${PREV_TEST_STATUS}'] = status
        destination['${PREV_TEST_MESSAGE}'] = message

    def _set_global_variable(self, name, value):
        self.namespace.variables.set_global(name, value)

    def report_suite_status(self, status, message):
        self.get_current_vars()['${SUITE_STATUS}'] = status
        self.get_current_vars()['${SUITE_MESSAGE}'] = message

    def start_test(self, test):
        self.namespace.start_test(test)
        self.output.start_test(test)

    def set_test_status_before_teardown(self, message, status):
        self.namespace.set_test_status_before_teardown(message, status)

    def get_handler(self, name):
        return self.namespace.get_handler(name)

    def start_keyword(self, keyword):
        self.output.start_keyword(keyword)

    def end_keyword(self, keyword):
        self.output.end_keyword(keyword)

    def warn(self, message):
        self.output.warn(message)

    def trace(self, message):
        self.output.trace(message)
<|endoftext|>


<commit_before>import os
import sys
import json

import requests
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET'])
def verify():
    # when the endpoint is registered as a webhook, it must echo back
    # the 'hub.challenge' value it receives in the query arguments
    if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
        if not request.args.get("hub.verify_token") == os.environ["VERIFY_TOKEN"]:
            return "Verification token mismatch", 403
        return request.args["hub.challenge"], 200

    return "Hello world", 200

@app.route('/', methods=['POST'])
def webhook():

    # endpoint for processing incoming messaging events

    data = request.get_json()
    log(data)  # you may not want to log every incoming message in production, but it's good for testing

    if data["object"] == "page":

        for entry in data["entry"]:
            for messaging_event in entry["messaging"]:

                if messaging_event.get("message"):  # someone sent us a message
                    pass
                if messaging_event.get("delivery"):  # delivery confirmation
                    pass

                if messaging_event.get("optin"):  # optin confirmation
                    pass

                if messaging_event.get("postback"):  # user clicked/tapped "postback" button in earlier message
                    sender_id = messaging_event["sender"]["id"]        # the facebook ID of the person sending you the message
                    recipient_id = messaging_event["recipient"]["id"]  # the recipient's ID, which should be your page's facebook ID
                    message_text = messaging_event["message"]["text"]  # the message's text

                    send_message(sender_id, "Welcome to Body & Face Clinic {{user_first_name}}!")

    return "ok", 200

def welcome_message():

    params = {
        "access_token": os.environ["PAGE_ACCESS_TOKEN"]
    }
    headers = {
        "Content-Type": "application/json"
    }
    data = json.dumps({
        "get_started" : {
            "payload":"GET_STARTED_PAYLOAD"
        }
    })
    r = requests.post("https://graph.facebook.com/v2.9/me/messages", params=params, headers=headers, data=data)
    if r.status_code != 200:
        log(r.status_code)
        log(r.text)

def send_message(recipient_id, message_text):

    log("sending message to {recipient}: {text}".format(recipient=recipient_id, text=message_text))

    params = {
        "access_token": os.environ["PAGE_ACCESS_TOKEN"]
    }
    headers = {
        "Content-Type": "application/json"
    }
    data = json.dumps({
        "recipient": {
            "id": recipient_id
        },
        "message": {
            "text": message_text
        }
    })
    r = requests.post("https://graph.facebook.com/v2.9/me/messages", params=params, headers=headers, data=data)
    if r.status_code != 200:
        log(r.status_code)
        log(r.text)

def log(message):  # simple wrapper for logging to stdout on heroku
    print str(message)
    sys.stdout.flush()

if __name__ == '__main__':
    app.run(debug=True)<commit_msg>Test8<commit_after>import os
import sys
import json

import requests
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET'])
def verify():
    # when the endpoint is registered as a webhook, it must echo back
    # the 'hub.challenge' value it receives in the query arguments
    if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
        if not request.args.get("hub.verify_token") == os.environ["VERIFY_TOKEN"]:
            return "Verification token mismatch", 403
        return request.args["hub.challenge"], 200

    return "Hello world", 200

@app.route('/', methods=['POST'])
def webhook():

    # endpoint for processing incoming messaging events

    data = request.get_json()
    log(data)  # you may not want to log every incoming message in production, but it's good for testing

    if data["object"] == "page":

        for entry in data["entry"]:
            for messaging_event in entry["messaging"]:

                if messaging_event.get("message"):  # someone sent us a message
                    sender_id = messaging_event["sender"]["id"]        # the facebook ID of the person sending you the message
                    recipient_id = messaging_event["recipient"]["id"]  # the recipient's ID, which should be your page's facebook ID
                    message_text = messaging_event["message"]["text"]  # the message's text

                    send_message(sender_id, "Welcome to Body & Face Clinic {{user_first_name}}!")
                if messaging_event.get("delivery"):  # delivery confirmation
                    pass

                if messaging_event.get("optin"):  # optin confirmation
                    pass

                if messaging_event.get("postback"):  # user clicked/tapped "postback" button in earlier message
                    pass

    return "ok", 200

def welcome_message():

    params = {
        "access_token": os.environ["PAGE_ACCESS_TOKEN"]
    }
    headers = {
        "Content-Type": "application/json"
    }
    data = json.dumps({
        "get_started" : {
            "payload":"GET_STARTED_PAYLOAD"
        }
    })
    r = requests.post("https://graph.facebook.com/v2.9/me/messages", params=params, headers=headers, data=data)
    if r.status_code != 200:
        log(r.status_code)
        log(r.text)

def send_message(recipient_id, message_text):

    log("sending message to {recipient}: {text}".format(recipient=recipient_id, text=message_text))

    params = {
        "access_token": os.environ["PAGE_ACCESS_TOKEN"]
    }
    headers = {
        "Content-Type": "application/json"
    }
    data = json.dumps({
        "recipient": {
            "id": recipient_id
        },
        "message": {
            "text": message_text
        }
    })
    r = requests.post("https://graph.facebook.com/v2.9/me/messages", params=params, headers=headers, data=data)
    if r.status_code != 200:
        log(r.status_code)
        log(r.text)

def log(message):  # simple wrapper for logging to stdout on heroku
    print str(message)
    sys.stdout.flush()

if __name__ == '__main__':
    app.run(debug=True)<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.test import TestCase

from .. import geocoder

FAILING_POSTCODES = [
    'LE1 5BU',
    'W1J 6BD',
    'CF11 5EQ',
    'EN8 9XB',
    'WA10 1QW',
    'LE15 6QH',
    'EC2N 2BR',
    'ST6 1AW',
    'UB4 0PU',
    'B93 ODX',
    'KT1 2PS',
    'TA1 1RL',
    'PE29 3TD',
    'NW6 2DD',
    'W1T 6AF',
    'L2 5JE',
    'SW1V 1EH',
    'WD17 1DR',
    'SE1 7UJ',
    'NP13 1YB',
    'PO9 1UL',
    'LS1 3BG',
    'BL9 0DX',
    'CM20 1ND',
    'PO9 1PA',
    'WA7 2HF',
    'CH41 5JF',
    'RG1 1SH',
    'DA12 1BQ',
    'LN1 1UW',
    'CF11 9LU',
    'NP16 3EF',
    'BD21 3AG',
    'PE21 6QL',
    'B3 3SH',
    'SO15 2UT',
    'CT9 2QT',
    'NN10 0PT',
    'BH14 9DY',
    'ME14 1JE',
    'RH11 7AF',
    'LN2 1DA',
    'WD24 4AQ',
    'N1 1RY',
    'LS2 8BA',
    'L2 0XG',
    'LN5 7PS',
    'BS1 4LY',
    'BB2 6AS',
    'N3 1LQ',
    'AL5 2SW',
    'SA15 3AL',
    'HU1 2AD',
    'BD21 3DT',
    'RG41 3AT',
    'NE63 8RL',
    'S65 1AA',
    'OX1 1TL',
    'YO8 4PX',
    'NE6 2HL',
    'YO1 6HP',
    'SO1 2XQ',
    'CH65 0HW',
    'N1 8UY',
    'SP2 7WP',
    'NN4 7SH',
    'LS12 6LN',
    'OL13 9AN',
    'SE5 0HF',
    'OL6 6DL',
    'WN1 1NG',
    'IP4 1NF',
    'L2 0NB',
    'TR1 2EY',
    'CA28 7NR',
    'ME4 4LY',
    'CH7 1BJ',
    'N7 9PD',
    'HD1 1QB',
    'BS1 5TR',
    'L2 2BX',
    'S80 1JE',
    'SE13 5LA',
    'LL65 1UR',
    'RM1 3LT',
    'SN1 2HG',
    'IG1 1TP',
    'TQ6 9PT',
    'ST1 1HQ',
    'N1 6PA',
    'SS17 7JL',
    'NR30 2JP',
    'SS1 1BB',
    'E15 4BX',
    'WS13 6LW',
    'M60 0AG',
    'MK9 2UB',
    'CR9 2ER',
    'WD17 1ST',
    'NN8 4JW',
    'SA13 1HX',
    'WV7 3HA',
    'SL6 8BE',
    'L11 8PN',
    'SG1 1AF',
    'W1A 3AE',
    'TF11 1JP',
    'CF47 8BU',
    'L11 1JS',
    'SL11 8NX',
    'SG7 6BD',
    'LL30 2T',
    'DN1 2DP',
    'EC4N 7DZ',
    'RH5 6BX',
    'HA1 1EJ',
    'KT1 2AD',
    'W14 8TH',
    'NW5 1RS',
    'SA11 3LP',
    'HA0 3NF',
    'SA11 1LF',
    'EC2V 7AW',
    'WC2E 8HA',
    'DE14 1BP',
    'DL14 6FE',
    'CR9 3NG',
    'DN14 5AE',
    'B11 1HP',
    'NR32 1PG',
    'NG1 7EJ',
    'ME7 4NX',
    'SW1H 0RG',
    'BS1 6BB',
    'W14 0GL',
    'TR1 3FF',
    'PO19 1TH',
    'EX8 1HQ',
    'CT6 6LE',
    'DY1 1RY',
    'BB8 0BX',
    'CB2 1BY',
    'NR30 2QJ',
    'JE2 3WP',
    'MK9 2LJ',
    'HU1 3DZ',
    'SM1 4JH',
]

class GeocodeTestCase(TestCase):
    def test_failing_postcodes(self):
        passed = []
        failed = []
        for pc in FAILING_POSTCODES:
            try:
                point = geocoder.geocode(pc)
                passed.append(pc)
            except geocoder.PostcodeNotFound:
                failed.append(pc)
            except geocoder.GeocoderError as e:
                failed.append(pc)

        if failed:
            self.fail('failed to geocode %s of %s' % (len(failed),
                                                      len(FAILING_POSTCODES)))
<commit_msg>remove incorrect postcodes from tests<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.test import TestCase

from .. import geocoder

FAILING_POSTCODES = [
    'LE1 5BU',
    'W1J 6BD',
    'EN8 9XB',
    'WA10 1QW',
    'LE15 6QH',
    'EC2N 2BR',
    'ST6 1AW',
    'UB4 0PU',
    'B93 ODX',
    'KT1 2PS',
    'TA1 1RL',
    'PE29 3TD',
    'NW6 2DD',
    'W1T 6AF',
    'SW1V 1EH',
    'WD17 1DR',
    'SE1 7UJ',
    'NP13 1YB',
    'PO9 1UL',
    'LS1 3BG',
    'BL9 0DX',
    'CM20 1ND',
    'PO9 1PA',
    'WA7 2HF',
    'CH41 5JF',
    'RG1 1SH',
    'DA12 1BQ',
    'LN1 1UW',
    'BD21 3AG',
    'PE21 6QL',
    'B3 3SH',
    'SO15 2UT',
    'CT9 2QT',
    'NN10 0PT',
    'BH14 9DY',
    'ME14 1JE',
    'RH11 7AF',
    'LN2 1DA',
    'WD24 4AQ',
    'N1 1RY',
    'LS2 8BA',
    'L2 0XG',
    'LN5 7PS',
    'BS1 4LY',
    'BB2 6AS',
    'N3 1LQ',
    'AL5 2SW',
    'SA15 3AL',
    'HU1 2AD',
    'BD21 3DT',
    'RG41 3AT',
    'NE63 8RL',
    'S65 1AA',
    'OX1 1TL',
    'YO8 4PX',
    'NE6 2HL',
    'YO1 6HP',
    'CH65 0HW',
    'N1 8UY',
    'NN4 7SH',
    'LS12 6LN',
    'OL13 9AN',
    'SE5 0HF',
    'OL6 6DL',
    'WN1 1NG',
    'IP4 1NF',
    'L2 0NB',
    'TR1 2EY',
    'CA28 7NR',
    'ME4 4LY',
    'CH7 1BJ',
    'N7 9PD',
    'HD1 1QB',
    'BS1 5TR',
    'L2 2BX',
    'S80 1JE',
    'SE13 5LA',
    'LL65 1UR',
    'RM1 3LT',
    'SN1 2HG',
    'IG1 1TP',
    'TQ6 9PT',
    'ST1 1HQ',
    'N1 6PA',
    'SS17 7JL',
    'NR30 2JP',
    'SS1 1BB',
    'E15 4BX',
    'WS13 6LW',
    'M60 0AG',
    'MK9 2UB',
    'CR9 2ER',
    'WD17 1ST',
    'NN8 4JW',
    'SA13 1HX',
    'WV7 3HA',
    'SL6 8BE',
    'SG1 1AF',
    'W1A 3AE',
    'CF47 8BU',
    'L11 1JS',
    'SG7 6BD',
    'DN1 2DP',
    'EC4N 7DZ',
    'RH5 6BX',
    'HA1 1EJ',
    'KT1 2AD',
    'W14 8TH',
    'NW5 1RS',
    'SA11 3LP',
    'HA0 3NF',
    'SA11 1LF',
    'WC2E 8HA',
    'DE14 1BP',
    'DL14 6FE',
    'CR9 3NG',
    'DN14 5AE',
    'NR32 1PG',
    'NG1 7EJ',
    'ME7 4NX',
    'SW1H 0RG',
    'BS1 6BB',
    'W14 0GL',
    'TR1 3FF',
    'PO19 1TH',
    'EX8 1HQ',
    'CT6 6LE',
    'DY1 1RY',
    'BB8 0BX',
    'CB2 1BY',
    'NR30 2QJ',
    'JE2 3WP',
    'MK9 2LJ',
    'HU1 3DZ',
    'SM1 4JH',
]

class GeocodeTestCase(TestCase):
    def test_failing_postcodes(self):
        passed = []
        failed = []
        for pc in FAILING_POSTCODES:
            try:
                point = geocoder.geocode(pc)
                passed.append(pc)
            except geocoder.PostcodeNotFound:
                failed.append(pc)
            except geocoder.GeocoderError as e:
                failed.append(pc)

        if failed:
            self.fail('failed to geocode %s of %s' % (len(failed),
                                                      len(FAILING_POSTCODES)))
<|endoftext|>


<commit_before>from django.db import models
from django.db.models.fields import CharField, DateField

from django.contrib.auth.models import User

class GoogleApiToken(models.Model):
    user = models.ForeignKey(User, related_name='google_api_tokens', on_delete=models.CASCADE)
    token = CharField(max_length=700)
    date_created = DateField(auto_now_add=True)
<commit_msg>changed models.py to contain new model<commit_after>from django.db import models

from django.contrib.auth.models import User
from django.forms import CharField

class GoogleApiToken(models.Model):
    user = models.ForeignKey(User, related_name='google_api_tokens', on_delete=models.CASCADE)
    token = models.CharField(max_length=700)
    date_created = models.DateField(auto_now_add=True)

class LiveGoogleSheetSchedule(models.Model):
    export_config_id = models.CharField(length=250, db_index=True)
    is_active = models.BooleanField(default=True)
    start_time = models.IntegerField(default=200)
    google_sheet_id = CharField(length=250)
<|endoftext|>


<commit_before>"""Extract data from rw.py experiments to a .csv file"""
import os
import argparse
import h5py
import pandas as pd
import numpy as np

parser = argparse.ArgumentParser(
        description="Simulate a Rescorla Wagner experiment",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
        )
parser.add_argument(
        "--hdf", type=str,
        help="Name of hdf5 file"
        )
parser.add_argument(
        "--names", type=str, nargs='+',
        help="Names of .csv"
        )
parser.add_argument(
        "--paths", type=str, nargs='+',
        help="Paths of data to traverse. Use '*' to select all leaves"
        )
parser.add_argument(
        "--dims", type=int, nargs='+',
        help="Dimensionality of data expected for each path"
        )
args = parser.parse_args()

# Arg processing
hdf = h5py.File(args.hdf, 'r')
names = args.names
paths = args.paths
dims = args.dims

for dim in dims:
    if dim < 0: raise ValueError("dim can't be negative")
    if dim > 1: raise ValueError("dim can't be greater than 1")

# Build up the tree to traverse
# get the data and write it
for path, name, dim in zip(paths, names, dims):
    parts = path.split('*')
    tree = None
    for part in parts[:-1]:  ## Hide last to avoid calling .keys() on it
        if tree is None:
            tree = hdf[part].keys()
        else:
            tree = [
                    os.path.join(leave, key)
                    for leave in tree
                    for key in hdf[leave].keys()
                    ]
    tree = [leave + parts[-1] for leave in tree]   ## Add the stat to extract

    extracted = []
    for leave in tree:
        extracted.append(hdf[leave].value)

    undertree = []
    for leave in tree:
        parts = leave.split('/')
        undertree.append('_'.join(parts))

    if dim == 0:
        data = np.squeeze(np.asarray(extracted))
        df = pd.DataFrame(data={parts[-1] : data})
        df['path'] = undertree
    else:
        maxl = np.max([len(ext) for ext in extracted])
        data = np.zeros([maxl, len(extracted)])
        for j, ext in enumerate(extracted):
            data[:len(ext),j] = ext
        df = pd.DataFrame(data=data.transpose(),
                columns=[str(parts[-1])+str(i) for i in range(maxl)]
                )
        df['path'] = undertree

    df.to_csv(name, index=False, float_format='%.8f')
<commit_msg>Doc improvements.<commit_after>"""Extract data from experiments to a .csv file"""
import os
import argparse
import h5py
import pandas as pd
import numpy as np

parser = argparse.ArgumentParser(
        description="Extract data from model experimental hdf files to csv tables",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
        )
parser.add_argument(
        "--hdf", type=str,
        help="Name of hdf5 file"
        )
parser.add_argument(
        "--names", type=str, nargs='+',
        help="Names of .csv"
        )
parser.add_argument(
        "--paths", type=str, nargs='+',
        help="Paths of data to traverse. Use '*' to select all leaves"
        )
parser.add_argument(
        "--dims", type=int, nargs='+',
        help="Dimensionality of data expected for each path"
        )
parser.add_argument(
        "--pad", type=int, default=-999999,
        help="Pad missing values with?"
        )
args = parser.parse_args()

# Arg processing
hdf = h5py.File(args.hdf, 'r')
names = args.names
paths = args.paths
dims = args.dims

for dim in dims:
    if dim < 0: raise ValueError("dim can't be negative")
    if dim > 1: raise ValueError("dim can't be greater than 1")

# Build up the tree to traverse
# get the data and write it
for path, name, dim in zip(paths, names, dims):
    parts = path.split('*')
    tree = None
    for part in parts[:-1]:  ## Hide last to avoid calling .keys() on it
        if tree is None:
            tree = hdf[part].keys()
        else:
            tree = [
                    os.path.join(leave, key)
                    for leave in tree
                    for key in hdf[leave].keys()
                    ]
    tree = [leave + parts[-1] for leave in tree]   ## Add the stat to extract

    extracted = []
    for leave in tree:
        extracted.append(hdf[leave].value)

    undertree = []
    for leave in tree:
        parts = leave.split('/')
        undertree.append('_'.join(parts))

    if dim == 0:
        data = np.squeeze(np.asarray(extracted))
        df = pd.DataFrame(data={parts[-1] : data})
        df['path'] = undertree
    else:
        maxl = np.max([len(ext) for ext in extracted])
        data = np.zeros([maxl, len(extracted)])
        for j, ext in enumerate(extracted):
            diff = maxl - len(ext)
            if diff > 0:
                ext = np.concatenate([ext, np.repeat(args.pad, diff)])
            data[:,j] = ext
        df = pd.DataFrame(data=data.transpose(),
                columns=[str(parts[-1])+str(i) for i in range(maxl)]
                )
        df['path'] = undertree

    df.to_csv(name, index=False, float_format='%.8f')
<|endoftext|>


<commit_before>from pprint import pprint

from django.db import connections
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.shortcuts import render
from django.views import View

import lotes.models
from lotes.views.lote.conserto_lote import dict_conserto_lote

import cd.forms

class RetirarParcial(PermissionRequiredMixin, View):

    def __init__(self, mobile=False):
        self.mobile = mobile
        self.permission_required = 'lotes.can_inventorize_lote'
        self.Form_class = cd.forms.RetirarParcialForm
        if self.mobile:
            self.template_name = 'cd/retirar_parcial_m.html'
        else:
            self.template_name = 'cd/retirar_parcial.html'
        self.title_name = 'Retirar lote parcial'

    def mount_context(self, request, form):
        cursor = connections['so'].cursor()
        context = {}

        lote = form.cleaned_data['lote']
        periodo = lote[:4]
        ordem_confeccao = lote[-5:]
        quant_retirar = form.cleaned_data['quant']
        identificado = form.cleaned_data['identificado']

        lote_sys = lotes.models.posicao_get_item(
            cursor, periodo, ordem_confeccao)

        lote_rec = lotes.models.Lote.objects.get(lote=lote)

        endereco = lote_rec.local
        context.update({
            'op': lote_rec.op,
            'lote_referencia': lote_rec.lote,
            'referencia': lote_rec.referencia,
            'cor': lote_rec.cor,
            'tamanho': lote_rec.tamanho,
            'qtd': lote_rec.qtd,
            'local': lote_rec.local,
            'quant_retirar': quant_retirar,
            })

        if identificado:
            form.data['identificado'] = None
            form.data['lote'] = None
            if lote != identificado:
                context.update({
                    'erro': 'A confirmação é bipando o mesmo lote. '
                            'Identifique o lote novamente.'})
                return context

            data = dict_conserto_lote(
                request, lote, '63', 'out', quant_retirar)

            if data['error_level'] > 0:
                level = data['error_level']
                erro = data['msg']
                context.update({
                    'concerto_erro':
                        f'Erro ao retirar {quant_retirar} '
                        f'peça{"s" if quant_retirar > 1 else ""} do '
                        f'concerto: {level} - "{erro}"',
                })
                # como o lote não será realmente retirado,
                # não precisa esse teste
                # if level not in [1, 2]:
                #     return context

            # retirada parcial não tira o lote do endereço
            # lote_rec.local = None
            # lote_rec.local_usuario = request.user
            # lote_rec.save()

            context['identificado'] = identificado
        else:
            context['lote'] = lote
            if lote_rec.local is not None:
                context['confirma'] = True
                form.data['identificado'] = form.data['lote']
            form.data['lote'] = None

        if not endereco:
            return context

        lotes_no_local = lotes.models.Lote.objects.filter(
            local=endereco).order_by(
                '-local_at'
                ).values(
                    'op', 'lote', 'qtd',
                    'referencia', 'cor', 'tamanho',
                    'local_at', 'local_usuario__username')
        if lotes_no_local:
            q_itens = 0
            for row in lotes_no_local:
                q_itens += row['qtd']
            context.update({
                'q_lotes': len(lotes_no_local),
                'q_itens': q_itens,
                'headers': ('Bipado em', 'Bipado por',
                            'Lote', 'Quant.',
                            'Ref.', 'Cor', 'Tam.', 'OP'),
                'fields': ('local_at', 'local_usuario__username',
                           'lote', 'qtd',
                           'referencia', 'cor', 'tamanho', 'op'),
                'data': lotes_no_local,
                })

        return context

    def get(self, request, *args, **kwargs):
        context = {'titulo': self.title_name}
        form = self.Form_class()
        context['form'] = form
        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):
        context = {'titulo': self.title_name}
        form = self.Form_class(request.POST)
        if form.is_valid():
            data = self.mount_context(request, form)
            context.update(data)
        context['form'] = form
        return render(request, self.template_name, context)

class RetirarParcialMobile(RetirarParcial):

    def __init__(self, mobile=True):
        super(RetirarParcialMobile, self).__init__(mobile=mobile)
<commit_msg>tualizar  tabela de lotes com a retirada de conserto<commit_after>from pprint import pprint

from django.db import connections
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.shortcuts import render
from django.views import View

import lotes.models
from lotes.views.lote.conserto_lote import dict_conserto_lote

import cd.forms

class RetirarParcial(PermissionRequiredMixin, View):

    def __init__(self, mobile=False):
        self.mobile = mobile
        self.permission_required = 'lotes.can_inventorize_lote'
        self.Form_class = cd.forms.RetirarParcialForm
        if self.mobile:
            self.template_name = 'cd/retirar_parcial_m.html'
        else:
            self.template_name = 'cd/retirar_parcial.html'
        self.title_name = 'Retirar lote parcial'

    def mount_context(self, request, form):
        cursor = connections['so'].cursor()
        context = {}

        lote = form.cleaned_data['lote']
        periodo = lote[:4]
        ordem_confeccao = lote[-5:]
        quant_retirar = form.cleaned_data['quant']
        identificado = form.cleaned_data['identificado']

        lote_sys = lotes.models.posicao_get_item(
            cursor, periodo, ordem_confeccao)

        lote_rec = lotes.models.Lote.objects.get(lote=lote)

        endereco = lote_rec.local
        context.update({
            'op': lote_rec.op,
            'lote_referencia': lote_rec.lote,
            'referencia': lote_rec.referencia,
            'cor': lote_rec.cor,
            'tamanho': lote_rec.tamanho,
            'qtd': lote_rec.qtd,
            'local': lote_rec.local,
            'quant_retirar': quant_retirar,
            })

        if identificado:
            form.data['identificado'] = None
            form.data['lote'] = None
            if lote != identificado:
                context.update({
                    'erro': 'A confirmação é bipando o mesmo lote. '
                            'Identifique o lote novamente.'})
                return context

            data = dict_conserto_lote(
                request, lote, '63', 'out', quant_retirar)

            if data['error_level'] > 0:
                level = data['error_level']
                erro = data['msg']
                context.update({
                    'concerto_erro':
                        f'Erro ao retirar {quant_retirar} '
                        f'peça{"s" if quant_retirar > 1 else ""} do '
                        f'concerto: {level} - "{erro}"',
                })
                if level not in [1, 2]:
                    return context

            # retirada parcial não tira o lote do endereço, mas
            # ajusta quantidades
            lote_rec.conserto -= quant_retirar
            lote_rec.local_usuario = request.user
            lote_rec.save()

            context['identificado'] = identificado
        else:
            context['lote'] = lote
            if lote_rec.local is not None:
                context['confirma'] = True
                form.data['identificado'] = form.data['lote']
            form.data['lote'] = None

        if not endereco:
            return context

        lotes_no_local = lotes.models.Lote.objects.filter(
            local=endereco).order_by(
                '-local_at'
                ).values(
                    'op', 'lote', 'qtd',
                    'referencia', 'cor', 'tamanho',
                    'local_at', 'local_usuario__username')
        if lotes_no_local:
            q_itens = 0
            for row in lotes_no_local:
                q_itens += row['qtd']
            context.update({
                'q_lotes': len(lotes_no_local),
                'q_itens': q_itens,
                'headers': ('Bipado em', 'Bipado por',
                            'Lote', 'Quant.',
                            'Ref.', 'Cor', 'Tam.', 'OP'),
                'fields': ('local_at', 'local_usuario__username',
                           'lote', 'qtd',
                           'referencia', 'cor', 'tamanho', 'op'),
                'data': lotes_no_local,
                })

        return context

    def get(self, request, *args, **kwargs):
        context = {'titulo': self.title_name}
        form = self.Form_class()
        context['form'] = form
        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):
        context = {'titulo': self.title_name}
        form = self.Form_class(request.POST)
        if form.is_valid():
            data = self.mount_context(request, form)
            context.update(data)
        context['form'] = form
        return render(request, self.template_name, context)

class RetirarParcialMobile(RetirarParcial):

    def __init__(self, mobile=True):
        super(RetirarParcialMobile, self).__init__(mobile=mobile)
<|endoftext|>


<commit_before>VERSION = '0.0.5'
<commit_msg>Bump version<commit_after>VERSION = '0.0.6'
<|endoftext|>


<commit_before>#!/usr/bin/env python

import tornado.wsgi
import tornado.web

import wsgiref.simple_server
from main import MainAPI

if __name__ == "__main__":
    apiApp = MainAPI()
    wsgi_app = tornado.wsgi.WSGIAdapter(apiApp.application)
    server = wsgiref.simple_server.make_server('', 8888, wsgi_app)
    server.serve_forever()
<commit_msg>updating app file<commit_after>import tornado.wsgi
import tornado.web

from main import MainAPI

if __name__ == "__main__":
    apiApp = MainAPI()
    wsgi_app = tornado.wsgi.WSGIAdapter(apiApp.application)
    # server = wsgiref.simple_server.make_server('', 8888, wsgi_app)
    # server.serve_forever()
<|endoftext|>


<commit_before>
import logging
logging.basicConfig(level=logging.DEBUG)
import sys
import os.path
import collections
import subprocess

from . import core
from .backend import gpass
from . import plugins

logger = logging.getLogger(__name__)

def main():
    root = core.Root()
    root.mount("", gpass.PassDir(""))
    modules = [ plg(root) for plg in plugins.PLUGINS ]
    actions = collections.OrderedDict()
    for m in modules:
        for k in dir(m):
            if k.startswith("do_"):
                actions[k[3:]] = actions.get(k[3:], []) + [getattr(m, k)]
    if len(sys.argv) < 2:
        print("Usage:")
        print("  %s COMMAND [ARGS ...]" % sys.argv[0])
        print("  %s PATH ..." % sys.argv[0])
        print("")
        print("Commands:")
        print("")
        print("PATH")
        print("   Copy value at PATH to clipboard and erase after some time.")
        for k,v in actions.items():
            print(k)
            for fn in v:
                if hasattr(fn, "__doc__") and fn.__doc__:
                    print("   %s" % fn.__doc__.strip())
    elif sys.argv[1] in actions:
        for fn in actions.get(sys.argv[1]):
            fn(*sys.argv[2:])
    else:
        node = root.query(*sys.argv[1:])
        if node is None:
            logger.error("path not found: %s", "/".join(sys.argv[1:]))
            return
        value = node.get()
        if value is None:
            logger.error("value not found: %s", "/".join(sys.argv[1:]))
            return
        clip = subprocess.Popen("xclip -selection clipboard".split(), stdin=subprocess.PIPE)
        clip.communicate(input=value.value.encode("utf-8"))
        eraser = os.path.abspath(os.path.join(os.path.split(__file__)[0], "clipboarderaser.py"))
        subprocess.Popen(["/usr/bin/env", "python", eraser])

<commit_msg>improve security by preventing coredumps<commit_after>
import logging
logging.basicConfig(level=logging.DEBUG)
import sys
import os.path
import collections
import subprocess
import ctypes

from . import core
from .backend import gpass
from . import plugins

logger = logging.getLogger(__name__)

def main():
    if True:
        PR_SET_DUMPABLE = 4
        ctypes.CDLL('libc.so.6').prctl(PR_SET_DUMPABLE, 0)
    root = core.Root()
    root.mount("", gpass.PassDir(""))
    modules = [ plg(root) for plg in plugins.PLUGINS ]
    actions = collections.OrderedDict()
    for m in modules:
        for k in dir(m):
            if k.startswith("do_"):
                actions[k[3:]] = actions.get(k[3:], []) + [getattr(m, k)]
    if len(sys.argv) < 2:
        print("Usage:")
        print("  %s COMMAND [ARGS ...]" % sys.argv[0])
        print("  %s PATH ..." % sys.argv[0])
        print("")
        print("Commands:")
        print("")
        print("PATH")
        print("   Copy value at PATH to clipboard and erase after some time.")
        for k,v in actions.items():
            print(k)
            for fn in v:
                if hasattr(fn, "__doc__") and fn.__doc__:
                    print("   %s" % fn.__doc__.strip())
    elif sys.argv[1] in actions:
        for fn in actions.get(sys.argv[1]):
            fn(*sys.argv[2:])
    else:
        node = root.query(*sys.argv[1:])
        if node is None:
            logger.error("path not found: %s", "/".join(sys.argv[1:]))
            return
        value = node.get()
        if value is None:
            logger.error("value not found: %s", "/".join(sys.argv[1:]))
            return
        clip = subprocess.Popen("xclip -selection clipboard".split(), stdin=subprocess.PIPE)
        clip.communicate(input=value.value.encode("utf-8"))
        eraser = os.path.abspath(os.path.join(os.path.split(__file__)[0], "clipboarderaser.py"))
        subprocess.Popen(["/usr/bin/env", "python", eraser])

<|endoftext|>


<commit_before>import json
import os
import requests
import yaml
import xmltodict

from fabric.colors import (
    green,
    yellow,
)
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.wait import TimeoutException

from lib.folder import get_test_folder
from lib.error import TaskError
from lib.siteinfo import SiteInfo

class BrowserDriver(object):

    def __init__(self, site_info, test_folder=None):
        self.browser = None
        self._site_info = site_info
        self.URL = 'url'
        self.TITLE = 'title'
        # Use the default location if not supplied
        if not test_folder:
            test_folder = get_test_folder()
        file_name = os.path.join(
            test_folder, '{}.yaml'.format(self._site_info.site_name)
        )
        self.data = self._load(file_name)
        if self.data:
            self._check_urls(file_name)

    def _create_browser(self):
        if not self.browser:
            self.browser = webdriver.Firefox()  # Get local session of firefox

    def _check_urls(self, file_name):
        for item in self.data['urls']:
            if not self.URL in item:
                raise TaskError(
                    "Each item in the list of 'urls' should have a "
                    "'{}': {}".format(self.URL, file_name)
                )
            if not self.TITLE in item:
                raise TaskError(
                    "Each item in the list of 'urls' should have a "
                    "'{}': {}".format(self.TITLE, file_name)
                )

    def _get(self, url, title=None):
        print(yellow(url)),
        self.browser.get(url)
        if title:
            self._wait_for_page_to_load(url, title)
            print(green("  OK (match {})".format(title)))
        else:
            print(green("  OK (found {})".format(self.browser.title)))

    def _load(self, file_name):
        with open(file_name, 'r') as f:
            data = yaml.load(f)
        return data

    def _load_sitemap(self):
        result = []
        url = '{}{}'.format(self._site_info.url, 'sitemap.xml')
        response = requests.get(url)
        if response.ok:
            xml = xmltodict.parse(response.text)
            data = xml['urlset']['url']
            for item in data:
                result.append(item['loc'])
        else:
            prompt("No sitemap found: {}".format(url))
        return result

    def _wait_for_page_to_load(self, url, title):
        try:
            WebDriverWait(self.browser, 10).until(
                lambda driver: title.lower() in driver.title.lower()
            )
        except TimeoutException:
            raise TaskError(
                "Time out waiting for page with title '{}' "
                "to load: {}".format(title, url)
            )

    def test(self):
        if self.data:
            self._create_browser()
            urls = self.data['urls']
            if urls:
                # get the urls
                for item in urls:
                    path = item.get(self.URL)
                    if path == '/':
                        path = ''
                    if not path:
                        path = ''
                    sep = '/'
                    if not path:
                        sep = ''
                    url = '{}{}{}'.format(self._site_info.url, path, sep)
                    title = item.get(self.TITLE)
                    self._get(url, title)
            else:
                # no urls - so get the home URL
                self._get(self._site_info.url, 'home')
        else:
            print(green("Nothing to test..."))

    def test_sitemap(self):
        self._create_browser()
        urls = self._load_sitemap()
        urls.sort()
        for url in urls:
            self._get(url)

    def close(self):
        if self.browser:
            self.browser.close()
<commit_msg>task - ok - browse to all pages in the sitemap - do not verify ssl certificate<commit_after>import json
import os
import requests
import yaml
import xmltodict

from fabric.colors import (
    green,
    yellow,
)
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.wait import TimeoutException

from lib.folder import get_test_folder
from lib.error import TaskError
from lib.siteinfo import SiteInfo

class BrowserDriver(object):

    def __init__(self, site_info, test_folder=None):
        self.browser = None
        self._site_info = site_info
        self.URL = 'url'
        self.TITLE = 'title'
        # Use the default location if not supplied
        if not test_folder:
            test_folder = get_test_folder()
        file_name = os.path.join(
            test_folder, '{}.yaml'.format(self._site_info.site_name)
        )
        self.data = self._load(file_name)
        if self.data:
            self._check_urls(file_name)

    def _create_browser(self):
        if not self.browser:
            self.browser = webdriver.Firefox()  # Get local session of firefox

    def _check_urls(self, file_name):
        for item in self.data['urls']:
            if not self.URL in item:
                raise TaskError(
                    "Each item in the list of 'urls' should have a "
                    "'{}': {}".format(self.URL, file_name)
                )
            if not self.TITLE in item:
                raise TaskError(
                    "Each item in the list of 'urls' should have a "
                    "'{}': {}".format(self.TITLE, file_name)
                )

    def _get(self, url, title=None):
        print(yellow(url)),
        self.browser.get(url)
        if title:
            self._wait_for_page_to_load(url, title)
            print(green("  OK (match {})".format(title)))
        else:
            print(green("  OK (found {})".format(self.browser.title)))

    def _load(self, file_name):
        with open(file_name, 'r') as f:
            data = yaml.load(f)
        return data

    def _load_sitemap(self):
        result = []
        url = '{}{}'.format(self._site_info.url, 'sitemap.xml')
        response = requests.get(url, verify=False)
        if response.ok:
            xml = xmltodict.parse(response.text)
            data = xml['urlset']['url']
            for item in data:
                result.append(item['loc'])
        else:
            prompt("No sitemap found: {}".format(url))
        return result

    def _wait_for_page_to_load(self, url, title):
        try:
            WebDriverWait(self.browser, 10).until(
                lambda driver: title.lower() in driver.title.lower()
            )
        except TimeoutException:
            raise TaskError(
                "Time out waiting for page with title '{}' "
                "to load: {}".format(title, url)
            )

    def test(self):
        if self.data:
            self._create_browser()
            urls = self.data['urls']
            if urls:
                # get the urls
                for item in urls:
                    path = item.get(self.URL)
                    if path == '/':
                        path = ''
                    if not path:
                        path = ''
                    sep = '/'
                    if not path:
                        sep = ''
                    url = '{}{}{}'.format(self._site_info.url, path, sep)
                    title = item.get(self.TITLE)
                    self._get(url, title)
            else:
                # no urls - so get the home URL
                self._get(self._site_info.url, 'home')
        else:
            print(green("Nothing to test..."))

    def test_sitemap(self):
        self._create_browser()
        urls = self._load_sitemap()
        urls.sort()
        for url in urls:
            self._get(url)

    def close(self):
        if self.browser:
            self.browser.close()
<|endoftext|>