51Degrees Pipeline Python  4.1

51Degrees Pipeline for Python

client_side_evidence_custom_flow_element.py

This example demonstrates the creation of a custom flow element. In this case the flowElement takes the results of a client side form collecting date of birth, setting this as evidence on a flowData object to calculate a person's starsign. The flowElement also serves additional JavaScript which gets a user's geolocation and saves the latitude as a cookie. This latitude is also then passed in to the flowData to calculate if a person is in the northern or southern hemispheres.

1  # *********************************************************************
2  # This Original Work is copyright of 51 Degrees Mobile Experts Limited.
3  # Copyright 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close,
4  # Caversham, Reading, Berkshire, United Kingdom RG4 7BY.
5  #
6  # This Original Work is licensed under the European Union Public Licence (EUPL)
7  # v.1.2 and is subject to its terms as set out below.
8  #
9  # If a copy of the EUPL was not distributed with this file, You can obtain
10  # one at https://opensource.org/licenses/EUPL-1.2.
11  #
12  # The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
13  # amended by the European Commission) shall be deemed incompatible for
14  # the purposes of the Work and the provisions of the compatibility
15  # clause in Article 5 of the EUPL shall not apply.
16  #
17  # If using the Work as, or as part of, a network application, by
18  # including the attribution notice(s) required under Article 5 of the EUPL
19  # in the end user terms of the application under an appropriate heading,
20  # such notice(s) shall fulfill the requirements of that article.
21  # ********************************************************************
22 
23 
24 
32 
33 from fiftyone_pipeline_core.pipelinebuilder import PipelineBuilder
34 from fiftyone_pipeline_core.web import webevidence
35 from fiftyone_pipeline_core.basiclist_evidence_keyfilter import BasicListEvidenceKeyFilter
36 from fiftyone_pipeline_core.flowelement import FlowElement
37 from fiftyone_pipeline_core.elementdata_dictionary import ElementDataDictionary
38 
39 import json
40 
41 # Function to get star sign from month and day
42 def getStarSign(month, day):
43 
44  if (month == 1 and day <= 20) or (month == 12 and day >= 22):
45  return "capricorn"
46 
47  elif (month == 1 and day >= 21) or (month == 2 and day <= 18):
48  return "aquarius"
49 
50  elif (month == 2 and day >= 19) or (month == 3 and day <= 20):
51  return "pisces"
52 
53  elif (month == 3 and day >= 21) or (month == 4 and day <= 20):
54  return "aries"
55 
56  elif (month == 4 and day >= 21) or (month == 5 and day <= 20):
57  return "taurus"
58 
59  elif (month == 5 and day >= 21) or (month == 6 and day <= 20):
60  return "gemini"
61 
62  elif (month == 6 and day >= 22) or (month == 7 and day <= 22):
63  return "cancer"
64 
65  elif (month == 7 and day >= 23) or (month == 8 and day <= 23):
66  return "leo"
67 
68  elif (month == 8 and day >= 24) or (month == 9 and day <= 23):
69  return "virgo"
70 
71  elif (month == 9 and day >= 24) or (month == 10 and day <= 23):
72  return "libra"
73 
74  elif (month == 10 and day >= 24) or (month == 11 and day <= 22):
75  return "scorpio"
76 
77  elif (month == 11 and day >= 23) or (month == 12 and day <= 21):
78  return "sagittarius"
79 
80 
81 class AstrologyFlowElement(FlowElement):
82 
83  def __init__(self):
84 
85  super(AstrologyFlowElement, self).__init__()
86 
87  self.datakey = "astrology"
88 
89  # set the FLowElement's properties
90 
91  self.properties = {
92  "hemisphere": {
93  "type": 'string',
94  "description": "the user's hemisphere"
95  },
96  "starSign": {
97  "type": 'string',
98  "description": "the user's starsign"
99  },
100  "getLatitude": {
101  "type": 'javascript',
102  "description": "JavaScript used to get a user's latitude"
103  }
104  }
105 
106 
107  # The process_internal function is the core working of a flowElement.
108  # It takes FlowData, reads evidence and returns data.
109  def process_internal(self, flowdata):
110 
111  result = {}
112 
113  # Get the date of birth from the query string (submitted through
114  # a form on the client side)
115  dateOfBirth = flowdata.evidence.get("query.dateOfBirth")
116 
117  if dateOfBirth:
118 
119  dateOfBirth = dateOfBirth.split('-')
120 
121  month = int(dateOfBirth[1])
122  day = int(dateOfBirth[2])
123 
124  result["starSign"] = getStarSign(month, day)
125 
126 
127  # Serve some JavaScript to the user that will be used to save
128  # a cookie with the user's latitude in it
129  result["getLatitude"] = """
130  navigator.geolocation.getCurrentPosition(function(position) {
131  document.cookie = \"latitude=\" + position.coords.latitude;
132  console.log(document.cookie)
133  loadHemisphere();
134  });
135  """
136 
137  # Get the latitude from the above cookie
138  latitude = flowdata.evidence.get("cookie.latitude")
139 
140  # Calculate the hemisphere
141  if latitude:
142 
143  result["hemisphere"] = "Northern" if float(latitude) > 0 else "Southern"
144 
145  data = ElementDataDictionary(self, result)
146 
147  flowdata.set_element_data(data)
148 
149  def get_evidence_key_filter(self):
150  """
151  get_evidence_key_filter - A filter (in this case a basic list) stating which evidence
152  the flowElement is interested in
153  """
154  return BasicListEvidenceKeyFilter(["cookie.latitude", "query.dateOfBirth"])
155 
156 
157 # Add some callback settings for the page to make a request with extra evidence from the client side, in this case the Flask /json route we have made below
158 
159 javascriptBuilderSettings = {
160  "endpoint": "/json"
161 }
162 
163 # Make the pipeline and add the element we want to it
164 
165 myPipeline = (PipelineBuilder({"javascriptBuilderSettings": javascriptBuilderSettings})).add(AstrologyFlowElement()).build()
166 
167 from flask import Flask, request
168 
169 app = Flask(__name__)
170 
171 # Make a route that returns back JSON encded properties for client side scripts to pick up
172 
173 @app.route('/json', methods=['POST'])
174 def jsonroute():
175 
176  # Create the flowData object for the JSON route
177  flowData = myPipeline.create_flowdata()
178 
179  # Add any information from the request (headers, cookies and additional
180  # client side provided information)
181 
182  flowData.evidence.add_from_dict(webevidence(request))
183 
184  # Process the flowData
185 
186  flowData.process()
187 
188  # Return the JSON from the JSONBundler engine
189 
190  return json.dumps(flowData.jsonbundler.json)
191 
192 
193 @app.route('/')
194 def server():
195 
196  flowData = myPipeline.create_flowdata()
197 
198  # Add any information from the request (headers, cookies and additional
199  # client side provided information)
200 
201  flowData.evidence.add_from_dict(webevidence(request))
202 
203  # Process the flowData
204 
205  flowData.process()
206 
207  # Generate the HTML for the form that gets a user's starsign
208 
209  output = ""
210 
211  output += "<h1>Starsign</h1>"
212 
213  output += "<form><label for='dateOfBirth'>Date of birth</label><input type='date' name='dateOfBirth' id='dateOfBirth'><input type='submit'></form>"
214 
215 
216 
217  if (flowData.astrology.starSign):
218  output += "<p>Your starsign is " + flowData.astrology.starSign + "</p>"
219 
220  output += "<div id='hemispheretext'>"
221 
222  if (flowData.astrology.hemisphere):
223  output += "<p>Look at the " + flowData.astrology.hemisphere + " hemisphere stars tonight!</p>"
224 
225  output += "</div>"
226 
227  output += "<script>"
228 
229 
236 
237  output += flowData.javascriptbuilder.javascript
238 
239  output += """
240  const loadHemisphere = function() {
241  fod.complete(function (data) {
242  if(data.astrology.hemisphere) {
243  var para = document.createElement("p");
244  var text = document.createTextNode("Look at the " +
245  data.astrology.hemisphere + " hemisphere stars tonight");
246  para.appendChild(text);
247 
248  var element = document.getElementById("hemispheretext");
249  var child = element.lastElementChild;
250  while (child) {
251  element.removeChild(child);
252  child = element.lastElementChild;
253  }
254  element.appendChild(para);
255  }
256  })
257  };
258 
259  """
260 
261  output += "</script>"
262 
263  # Return the full output to the page
264 
265  return output