initial commit

This commit is contained in:
Michael Becker 2023-11-25 21:43:40 -05:00
parent 1195d69a2c
commit 3b3cc3341a
57 changed files with 994 additions and 0 deletions

14
mocha-mysql.py Normal file
View File

@ -0,0 +1,14 @@
import mysql.connector
from mocha.core import InstanceKey, InstanceReference
from mocha.oms import DatabaseOms
if __name__ == "__main__":
oms = MySQLDatabaseOms("localhost", 13306, "mocha_user", "9Q5eLsKfL5AciM4U", "mocha_test")
inst = oms.get_instance_by_key(InstanceKey(1, 1))
iaName = oms.get_instance_by_key(InstanceKey(4, 1))
val = oms.get_attribute_value(inst, iaName)
print(val)

10
mocha-web.py Normal file
View File

@ -0,0 +1,10 @@
from mocha.web.WebServer import WebServer
if __name__ == "__main__":
port = 8081
print("Mocha User Interface Service - running on port", port)
server = WebServer(("127.0.0.1", port))
server.serve_forever()

26
mocha/core/InstanceKey.py Normal file
View File

@ -0,0 +1,26 @@
class InstanceKey():
@staticmethod
def parse(val):
tup = val.split('$')
if len(tup) != 2:
return None
return InstanceKey(tup[0], tup[1])
def __init__(self, class_id : int, inst_id : int):
self.__class_id = class_id
self.__inst_id = inst_id
def get_class_index(self) -> int:
return self.__class_id
def get_instance_index(self) -> int:
return self.__inst_id
def __str__(self):
return str(self.get_class_index()) + '$' + str(self.get_instance_index())

View File

@ -0,0 +1,20 @@
from .InstanceKey import InstanceKey
class InstanceReference:
def __init__(self, dbid, inst_key : InstanceKey, global_id):
self.dbid = dbid
self.inst_key = inst_key
self.global_id = global_id
def get_dbid(self):
return self.dbid
def get_instance_key(self) -> InstanceKey:
return self.inst_key
def get_global_identifier(self):
return self.global_id.lower()
def __str__(self):
return str(self.inst_key) + ' ' + self.global_id

View File

@ -0,0 +1,16 @@
from .InstanceReference import InstanceReference
class TenantReference:
def __init__(self, tenant_name, global_id):
self.__tenant_name = tenant_name
self.__global_id = global_id
def get_instance(self) -> InstanceReference:
pass
def get_name(self):
return self.__tenant_name
def get_global_identifier(self):
return self.__global_id

3
mocha/core/__init__.py Normal file
View File

@ -0,0 +1,3 @@
from .InstanceKey import InstanceKey
from .InstanceReference import InstanceReference
from .TenantReference import TenantReference

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

4
mocha/oms/DatabaseOms.py Normal file
View File

@ -0,0 +1,4 @@
from .Oms import Oms
class DatabaseOms(Oms):
pass

View File

@ -0,0 +1,133 @@
from .Oms import Oms
from .DatabaseOms import DatabaseOms
from ..core import InstanceKey, InstanceReference, TenantReference
import mysql.connector
class MySQLDatabaseOms(DatabaseOms):
def __init__(self, hostname, port, username, password, database):
self.db = mysql.connector.connect(
host=hostname,
port=port,
user=username,
password=password,
database=database
)
def _call_proc(self, name, parms : tuple):
pass
def get_instance_by_key(self, key : InstanceKey):
mycur = self.db.cursor()
if key is None:
return None
#resu = mycur.execute("CALL mocha_get_instances(NULL)", multi=True)
resu = mycur.callproc("mocha_get_instance_by_key", (key.class_id, key.inst_id))
data = mycur.stored_results()
inst = None
# tuple: (id, class_id, inst_id, global_identifier)
for result in data:
for row in result:
inst_key = InstanceKey(row[1], row[2])
global_id = row[3]
inst = InstanceReference(row[0], inst_key, global_id)
return inst
def get_instances(self, of_class : InstanceReference = None):
mycur = self.db.cursor()
#resu = mycur.execute("CALL mocha_get_instances(NULL)", multi=True)
pclassid = None
if of_class is not None:
pclassid = of_class.get_instance_key().get_class_index()
resu = mycur.callproc("mocha_get_instances", (pclassid,))
data = mycur.stored_results()
"""
sql = "INSERT INTO customers (name, address) VALUES (%s, %s)"
val = [
('Peter', 'Lowstreet 4'),
('Amy', 'Apple st 652'),
('Hannah', 'Mountain 21'),
('Michael', 'Valley 345'),
('Sandy', 'Ocean blvd 2'),
('Betty', 'Green Grass 1'),
('Richard', 'Sky st 331'),
('Susan', 'One way 98'),
('Vicky', 'Yellow Garden 2'),
('Ben', 'Park Lane 38'),
('William', 'Central st 954'),
('Chuck', 'Main Road 989'),
('Viola', 'Sideway 1633')
]
mycursor.executemany(sql, val)
"""
insts = []
# tuple: (id, class_id, inst_id, global_identifier)
for result in data:
for row in result:
inst_key = row[0]
global_id = row[1]
insts.append({ "inst_key": InstanceKey.parse(inst_key), "global_identifier": global_id })
return insts
def get_attribute_value(self, inst, attr_inst, eff_date = None):
mycur = self.db.cursor()
#resu = mycur.execute("CALL mocha_get_instances(NULL)", multi=True)
resu = mycur.callproc("mocha_get_attribute_value", (inst.get_dbid(), attr_inst.get_dbid(), eff_date))
data = mycur.stored_results()
"""
sql = "INSERT INTO customers (name, address) VALUES (%s, %s)"
val = [
('Peter', 'Lowstreet 4'),
('Amy', 'Apple st 652'),
('Hannah', 'Mountain 21'),
('Michael', 'Valley 345'),
('Sandy', 'Ocean blvd 2'),
('Betty', 'Green Grass 1'),
('Richard', 'Sky st 331'),
('Susan', 'One way 98'),
('Vicky', 'Yellow Garden 2'),
('Ben', 'Park Lane 38'),
('William', 'Central st 954'),
('Chuck', 'Main Road 989'),
('Viola', 'Sideway 1633')
]
mycursor.executemany(sql, val)
"""
# tuple: (id, class_id, inst_id, global_identifier)
for result in data:
rows = result.fetchall()
for row in rows:
return row[0]
return None
def get_tenant_by_name(self, tenant_name : str) -> TenantReference:
mycur = self.db.cursor()
#resu = mycur.execute("CALL mocha_get_instances(NULL)", multi=True)
resu = mycur.callproc("mocha_get_tenant_by_name", (tenant_name, None))
data = mycur.stored_results()
for result in data:
rows = result.fetchall()
for row in rows:
global_id = row[0]
return TenantReference(tenant_name, global_id)
return None

14
mocha/oms/Oms.py Normal file
View File

@ -0,0 +1,14 @@
from ..core import InstanceKey, InstanceReference, TenantReference
class Oms:
def __init__(self):
pass
def get_instance_by_key(self, key : InstanceKey):
pass
def get_instances(self, of_class : InstanceReference = None):
pass
def get_tenant_by_name(self, tenant_name : str) -> TenantReference:
pass

3
mocha/oms/__init__.py Normal file
View File

@ -0,0 +1,3 @@
from .Oms import Oms
from .DatabaseOms import DatabaseOms
from .MySQLDatabaseOms import MySQLDatabaseOms

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

64
mocha/web/WebControl.py Normal file
View File

@ -0,0 +1,64 @@
from .XmlTag import XmlTag
class WebControl (XmlTag):
def __init__(self, tag_name):
XmlTag.__init__(self, tag_name)
def create_from_json(self, json):
if "components" in json:
for component in json["components"]:
wc = WebControl.from_json(component)
self.add(wc)
@staticmethod
def from_json(json):
ctl = None
if json["type"] == "box":
orientation = "vertical"
if "orientation" in json:
orientation = json["orientation"]
from .controls import Box
ctl = Box(orientation)
if json["type"] == "grid":
from .controls import Grid, GridRow, GridCell
ctl = Grid()
if "rows" in json:
for row in json["rows"]:
row_ctl = GridRow()
for cell in row["cells"]:
ctl1 = WebControl.from_json(cell)
if not ctl1 is None:
td = GridCell()
td.add(ctl1)
row_ctl.add(td)
ctl.add(row_ctl)
elif json["type"] == "label":
from .controls import Label
text = ""
if "text" in json:
text = json["text"]
ctl = Label(text)
elif json["type"] == "text":
from .controls import TextBox
ctl = TextBox()
elif json["type"] == "password":
from .controls import TextBox
ctl = TextBox("password")
if not ctl is None:
if "components" in json:
for component in json["components"]:
wc = WebControl.from_json(component)
ctl.add(wc)
print(json["type"] + " is " + str(ctl))
return ctl
def render_json(self):
return None

64
mocha/web/WebPage.py Normal file
View File

@ -0,0 +1,64 @@
from .WebControl import WebControl
from .WebStyleSheet import WebStyleSheet
from .XmlTag import XmlTag
class WebPage (WebControl):
def __init__(self):
WebControl.__init__(self, 'html')
self.__title = None
self.__body = XmlTag('body')
self.__head = XmlTag('head')
self.__style_sheet = WebStyleSheet()
self.add(self.__head)
self.__head.add(self.__style_sheet)
self.add(self.__body)
def create_from_json(self, json):
if "components" in json:
for component in json["components"]:
wc = WebControl.from_json(component)
self.get_body().add(wc)
if "title" in json:
self.set_title(json["title"])
def get_style_sheet(self):
return self.__style_sheet
def set_style_sheet(self, style_sheet):
self.__style_sheet = style_sheet
def get_head(self):
return self.__head
def get_body(self):
return self.__body
def get_title(self):
return self.__title
def set_title(self, value):
self.__title = value
def render_json(self):
return {
"title": "Not Found",
"components": None
}
def render_before_html(self):
title = self.get_title()
if title is None:
title = ""
html = """<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">"""
return html
def render_after_html(self):
html = """
</html>"""
return html

View File

@ -0,0 +1,264 @@
from functools import cached_property
from http.cookies import SimpleCookie
from http.server import BaseHTTPRequestHandler
from urllib.parse import parse_qsl, urlparse
import json
from ..oms import Oms
class WebRequestHandler(BaseHTTPRequestHandler):
def __init__(self, request, client_address, server):
BaseHTTPRequestHandler.__init__(self, request, client_address, server)
@cached_property
def url(self):
return urlparse(self.path)
@cached_property
def query_data(self):
return dict(parse_qsl(self.url.query))
@cached_property
def post_data(self):
content_length = int(self.headers.get("Content-Length", 0))
return self.rfile.read(content_length)
@cached_property
def form_data(self):
return dict(parse_qsl(self.post_data.decode("utf-8")))
@cached_property
def cookies(self):
return SimpleCookie(self.headers.get("Cookie"))
def respond_with_redirect(self, url):
self.send_response(302, "Found")
self.send_header("Location", url)
self.end_headers()
self.close_connection()
def respond_with_content(self, response_code, response_text, content_type, content):
self.send_response(response_code, response_text)
self.send_header("Content-Type", content_type)
self.send_header("Content-Length", len(content))
self.end_headers()
self.wfile.write(content.encode("utf-8"))
def get_oms(self) -> Oms:
from ..oms import MySQLDatabaseOms
if not hasattr(self, "__oms"):
self.__oms = None
if self.__oms is None:
self.__oms = MySQLDatabaseOms("localhost", 13306, "mocha_user", "9Q5eLsKfL5AciM4U", "mocha_test")
return self.__oms
def do_GET(self):
oms = self.get_oms()
default_tenant_name = "super"
path = self.url.path.split('/')
path = path[1:]
if (len(path) == 1 and path[0] == ""):
self.respond_with_redirect("/" + default_tenant_name)
return
if (len(path) > 0):
tenant_name = path[0]
if len(path) == 1:
self.respond_with_redirect("/madi/authgwy/" + tenant_name + "/login.htmld")
return
if len(path) > 1:
if tenant_name == "madi":
authgwy = path[1]
if authgwy == "authgwy":
if len(path) == 4:
tenant_name = path[2]
file_name = path[3]
tenant = oms.get_tenant_by_name(tenant_name)
if tenant is None:
pass
else:
print(tenant.get_name())
if file_name == "login.htmld":
from .pages import LoginWebPage
page = LoginWebPage()
self.respond_with_content(200, "OK", "application/xhtml+xml", page.render_html())
return
elif file_name == "tenant-config.xml":
content = self.get_tenant_config_xml(tenant_name)
self.respond_with_content(200, "OK", "application/xml", content)
return
elif file_name == "images":
if len(path) >= 5:
if path[4] == "signon.xml":
return self.respond_with_header_image(tenant_name)
else:
if len(path) > 1:
if path[1] == "d":
if len(path) > 2:
if path[2] == "home.htmld":
from .pages import HomeWebPage
page = HomeWebPage()
self.respond_with_content(200, "OK", "application/xhtml+xml", page.render_html())
jj = self.get_json_response()
if jj["result"] == "failure" and jj["remedy"] == "login":
self.respond_with_login_page(tenant_name)
return
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(self.get_response().encode("utf-8"))
def do_POST(self):
self.do_GET()
def respond_with_header_image(self, tenant_name):
return None
def respond_with_login_page(self, tenant_name):
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(self.get_response().encode("utf-8"))
def get_response(self):
jj = self.get_json_response()
if jj["result"] == "failure" and jj["remedy"] == "login":
self.respond_with_login_page()
return json.dumps(jj)
def get_singleline_xml(self, tag_name, content_dict):
sz = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>"""
sz += "<" + tag_name + " "
for key in content_dict:
val = content_dict[key]
sz += key + "=\"" + val + "\" "
sz += "/>"
return sz
def get_tenant_config_xml(self, tenant_name : str):
oms = self.get_oms()
tenant = oms.get_tenant_by_name(tenant_name)
return self.get_singleline_xml("mcu:Tenant_Config", {
"xmlns:mcu": "urn:net.alcetech.schemas.Mocha.UserInterface",
"Allow_Attachments_And_Documents_To_Be_Shared_With_Other_Mobile_Apps": "0",
"Apns_Allowed": "0",
"Canvas_Is_Enabled": "1",
"Canvas_Hex_Code": "#005cb9,#0875e1",
"Clear_Mobile_SSO_Webview_Cookies_on_Login": "0",
"Deter_Screenshots": "0",
"Disable_Add_To_Contact": "0",
"Disable_Importing_Attachments_From_Third-Party_Cloud_Services": "0",
"Disable_Location_Service": "0",
"Disable_Mail_To": "0",
"Disable_Voice_in_Assistant_on_Mobile": "1",
"Enable_Blue_Primary_Buttons": "0",
"Enable_Certificate_Based_SSO": "0",
"Enable_DOM_Storage": "0",
"Enable_Email_Annotations": "1",
"Enable_export_to_Worksheets": "1",
"Enable_Fingerprint_Authentication": "1",
"Enable_Geospace_Visualization": "0",
"Enable_Mobile_Browser_SSO_for_Native_Apps": "0",
"Enable_New_Profile": "0",
"Error_Message_for_Browser": "This Browser is not supported by Workday. Please contact your IT department.",
"Is_FedRAMP_Tenant": "0",
"Google_Cloud_Messaging_Project_Number": "739632724832",
"Hide_Links_to_Web_from_Deep_Linking_and_Inbox": "0",
"Login_URL": "https://wd5.myworkday.com/cityoforlando/login-saml2.flex",
"Logout_URL": "https://cityoforlando.okta.com",
"OMS_Note": "PROD - Powered by Workday",
"Pin_Auth_Enabled": "0",
"Pin_Max_Attempts": "0",
"Pin_Max_Length": "0",
"Pin_Min_Length": "0",
"Reset_Password_Online": "0",
"Show_Change_Password_Link": "1",
"Show_Forgotten_Password_Link": "0",
"SignOn_Custom_Message": "&lt;p&gt;City of Orlando - Production&lt;/p&gt;",
"SignOn_Message_Locale": "en_US",
"SignOn_Note": "&lt;p&gt;City of Orlando - Production&lt;/p&gt;",
"SignOn_Tenant_Logo_Url": "/cityoforlando/images/signon.xml",
"System_Confidence_Level": "PROD",
"System_Note": oms.get_attribute_value(tenant.get_instance(), oms.get_instance_by_global_identifier('')), # "Your system will be unavailable for a maximum of 3 hours during the next Weekly Service Update; starting on Friday, October 27, 2023 at 11:00 PM PDT (GMT-7) until Saturday, October 28, 2023 at 2:00 AM PDT (GMT-7).",
"Use_One_Time_Use_Link": "0"
})
def get_json_response(self):
path = self.url.path.split('/')
path = path[1:]
tenantName = path[0]
if tenantName == "madi":
authgwy = path[1]
if authgwy == "authgwy":
if len(path) == 4:
tenantName = path[2]
loginPage = path[3]
else:
# error out
return
else:
# error out
return
from ..core import InstanceKey
from ..oms import MySQLDatabaseOms
oms = MySQLDatabaseOms("localhost", 13306, "mocha_user", "9Q5eLsKfL5AciM4U", "mocha_test")
if len(path) > 3:
if path[1] == "api":
if path[2] == "instances":
ik = InstanceKey.parse(path[3])
inst = oms.get_instance_by_key(ik)
if inst is None:
jj = {
"result": "error",
"message": "invalid inst " + str(ik)
}
return jj
jj = {
"result": "success",
"iid": str(inst.get_instance_key()),
"gid": inst.get_global_identifier()
}
return jj
else:
jj = {
"result": "error",
"message": "invalid request"
}
return jj
else:
jj = {
"result": "error",
"message": "invalid request"
}
return jj

21
mocha/web/WebScript.py Normal file
View File

@ -0,0 +1,21 @@
from .XmlTag import XmlTag
class WebScript (XmlTag):
def __init__(self, content_type : str, **kwargs):
XmlTag.__init__(self, 'script')
self.add_attribute('type', content_type)
self.content_type = content_type
if "content" in kwargs:
self.targetUrl = None
self.set_content(kwargs["content"])
elif "targetUrl" in kwargs:
self.targetUrl = kwargs["targetUrl"]
self.add_attribute('src', targetUrl)
def get_content_type(self):
return self.content_type
def get_target_url(self):
return self.targetUrl

12
mocha/web/WebServer.py Normal file
View File

@ -0,0 +1,12 @@
from .WebRequestHandler import WebRequestHandler
class WebServer():
def __init__(self, tup):
self.__tup = tup
def serve_forever(self):
from http.server import HTTPServer
server = HTTPServer(self.__tup, WebRequestHandler)
server.serve_forever()

View File

@ -0,0 +1,50 @@
from .XmlTag import XmlTag
class WebStyleSheet (XmlTag):
def __init__(self):
XmlTag.__init__(self, 'style')
self.__rules = []
def add_class(self, names):
names_list = names.split(" ")
for name in names_list:
self.__classes.append(name)
def add_rule(self, selector, rule):
self.__rules.append((selector, rule))
def get_rules(self):
return self.__rules
def get_class(self):
if len(self.__classes) == 0:
return None
names = ""
for i in range(len(self.__classes)):
names += self.__classes[i]
if i < len(self.__classes) - 1:
names += ' '
return names
def render_html(self):
if len(self.get_content()) == 0:
return ""
return super().render_html()
def get_content(self):
html = ""
for rule in self.__rules:
selector = rule[0]
actual_rule = rule[1]
html += selector + " { "
for k in actual_rule:
v = actual_rule[k]
html += k + ": " + v + "; "
html += " }"
return html

View File

@ -0,0 +1,6 @@
class XmlAttribute:
def __init__(self, name, value):
self.name = name
self.value = value

80
mocha/web/XmlTag.py Normal file
View File

@ -0,0 +1,80 @@
from .XmlAttribute import XmlAttribute
from .XmlTagStyles import XmlTagStyles
class XmlTag:
def __init__(self, tag_name : str):
self.__tag_name = tag_name
self.__style = XmlTagStyles()
self.__attributes = []
self.__controls = []
self.__content = None
def add_attribute(self, name, value):
self.__attributes.append(XmlAttribute(name, value))
def add(self, ctl):
self.__controls.append(ctl)
def get_controls(self):
return self.__controls
def get_tag_name(self):
return self.__tag_name
def get_content(self):
return self.__content
def set_content(self, value):
self.__content = value
def get_style(self) -> XmlTagStyles:
return self.__style
def has_content_or_controls(self):
return not (self.get_content() is None and len(self.__controls) == 0)
def render_before_html(self):
html = "<" + self.get_tag_name()
if self.get_style().has_classes():
classname = self.get_style().get_class()
if not (classname is None or len(classname) == 0):
html += " class=\"" + classname + "\""
if self.get_style().has_rules():
rulestr = self.get_style().get_rules_css()
if not (rulestr is None or len(rulestr) == 0):
html += " style=\"" + rulestr + "\""
if (len(self.__attributes) > 0):
html += " "
for i in range(len(self.__attributes)):
attr = self.__attributes[i].name
html += attr + "=\"" + self.__attributes[i].value + "\""
if i < len(self.__attributes) - 1:
html += " "
if self.has_content_or_controls():
html += ">"
return html
def render_after_html(self):
if self.has_content_or_controls():
return "</" + self.get_tag_name() + ">"
else:
return " />"
def render_html(self):
html = ""
html += self.render_before_html()
if self.get_content() is None:
for ctl in self.get_controls():
if not ctl is None:
html += ctl.render_html()
else:
html += self.get_content()
html += self.render_after_html()
return html

38
mocha/web/XmlTagStyles.py Normal file
View File

@ -0,0 +1,38 @@
class XmlTagStyles:
def __init__(self):
self.__classes = []
self.__rules = dict()
def add_class(self, names):
names_list = names.split(" ")
for name in names_list:
self.__classes.append(name)
def add_rule(self, k, v):
self.__rules[k] = v
def get_rules(self):
return self.__rules
def get_class(self):
if len(self.__classes) == 0:
return None
names = ""
for i in range(len(self.__classes)):
names += self.__classes[i]
if i < len(self.__classes) - 1:
names += ' '
return names
def get_rules_css(self):
html = ""
for k in self.__rules:
v = rule[k]
html += k + ": " + v + "; "
return html
def has_rules(self):
return len(self.__rules) > 0
def has_classes(self):
return len(self.__classes) > 0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

12
mocha/web/controls/Box.py Normal file
View File

@ -0,0 +1,12 @@
from ..WebControl import WebControl
class Box (WebControl):
def __init__(self, orientation):
WebControl.__init__(self, "div")
self.get_style().add_class("uwt-box")
if orientation == "horizontal":
self.get_style().add_class("uwt-orientation-horizontal")
elif orientation == "vertical":
self.get_style().add_class("uwt-orientation-vertical")

View File

@ -0,0 +1,14 @@
from ..WebControl import WebControl
class Grid (WebControl):
def __init__(self):
WebControl.__init__(self, "table")
class GridRow (WebControl):
def __init__(self):
WebControl.__init__(self, "tr")
class GridCell (WebControl):
def __init__(self):
WebControl.__init__(self, "td")

View File

@ -0,0 +1,8 @@
from ..WebControl import WebControl
class Label (WebControl):
def __init__(self, text):
WebControl.__init__(self, "label")
self.set_content(text)

View File

@ -0,0 +1,17 @@
from ..WebControl import WebControl
class TextBox (WebControl):
def __init__(self, mode = None):
WebControl.__init__(self, "input")
if mode == "password":
self.add_attribute("type", "password")
else:
self.add_attribute("type", "text")
self.__mode = mode
def get_mode(self):
return self.__mode
def set_mode(self, value):
self.__mode = value

View File

@ -0,0 +1,4 @@
from .Box import Box
from .Grid import Grid, GridRow, GridCell
from .Label import Label
from .TextBox import TextBox

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,46 @@
from ..WebScript import WebScript
from ..WebPage import WebPage
class BaseWebPage (WebPage):
def __init__(self):
WebPage.__init__(self)
self.get_style_sheet().add_rule('table', { 'width': '100%' })
self.get_head().add(self.get_client_config_script())
def get_client_config_script(self):
return WebScript("text/javascript", content="""
// Add properties to mocha
window.mocha = window.mocha || {};
mocha.tenant = 'cityoforlando3';
mocha.clientOrigin = 'https://wd5-impl.workday.com';
mocha.language = 'en_US';
mocha.clientVersion = '0';
mocha.systemConfidenceLevel = 'PROD';
mocha.oauthAuthorizationPending = false;
mocha.proxyLoginEnabled = false;
mocha.maintenancePageUrl = 'https://wd5-impl.workday.com/wday/drs/outage?t=cityoforlando3';
mocha.deviceTrustDetailsUrl = '';
mocha.pendingAuthDetailsUrl = '';
mocha.webAuthnDetailsUrl = '';
mocha.enableBluePrimaryButtons = 'false';
// Construct init params for GWT app
mocha.initParams = {
authGatewayPath: '/wday/authgwy',
baseDir: '/wday/asset/ui-html/',
systemConfidenceLevel: 'PROD',
cdn: {
endpoint: 'wd5-impl.workdaycdn.com',
enabled: true,
allowed: true
},
proxyEnabled: false,
currentVersion: '20.0.04.045',
serviceType: 'authgwy',
loginAuthURL: '/cityoforlando3/login-auth.xml',
environment: 'Implementation - cityoforlando3',
environmentType: 'IMPL'
};
""")

View File

@ -0,0 +1,10 @@
from .BaseWebPage import BaseWebPage
class HomeWebPage(BaseWebPage):
def __init__(self):
BaseWebPage.__init__(self)
self.create_from_json({
})

View File

@ -0,0 +1,39 @@
from .BaseWebPage import BaseWebPage
class LoginWebPage(BaseWebPage):
def __init__(self):
BaseWebPage.__init__(self)
self.create_from_json({
"title": "Log In",
"components": [
{
"type": "grid",
"rows": [
{
"cells": [
{
"type": "label",
"text": "User _name"
},
{
"type": "text"
}
]
},
{
"cells": [
{
"type": "label",
"text": "_Password"
},
{
"type": "password"
}
]
}
]
}
]})

View File

@ -0,0 +1,2 @@
from .LoginWebPage import LoginWebPage
from .HomeWebPage import HomeWebPage

Binary file not shown.