From b0395b5293ed6fece92ba79ea801129823739c35 Mon Sep 17 00:00:00 2001 From: Norm Rasmussen Date: Tue, 22 Nov 2022 17:13:39 -0500 Subject: [PATCH] Finalized Confluence Script and Started Skuid --- CustomerNotes/Artera.md | 17 + CustomerNotes/Crayon.md | 2 +- CustomerNotes/Skuid.md | 8 + CustomerNotes/Talkspace.md | 7 + Scripts/API_Notes/SampleNotes/Flink.md | 160 +---- Scripts/API_Notes/conf_functionsonly.py | 35 +- Scripts/API_Notes/main_md2confluence.py | 118 ++++ .../API_Notes/main_md2confluence_allfiles.py | 127 ++++ Scripts/API_Notes/markdown_conv.py | 50 -- Scripts/API_Notes/md2conf_testdebug.py | 116 ++++ Scripts/G2_Unenroll/fix_unenroll.py | 87 +-- Scripts/G2_Unenroll/skuid_lp.py | 27 + Scripts/Skuid_LPs/.DS_Store | Bin 0 -> 6148 bytes Scripts/Skuid_LPs/find_completed.py | 28 + Scripts/Skuid_LPs/skuid_05lp.csv | 574 ++++++++++++++++++ Scripts/TodoMD/todo.py | 24 +- Timetagger/_timetagger/users/norm~bm9ybQ==.db | Bin 192512 -> 196608 bytes Todos.md | 4 +- 18 files changed, 1080 insertions(+), 304 deletions(-) create mode 100644 CustomerNotes/Artera.md create mode 100644 Scripts/API_Notes/main_md2confluence.py create mode 100644 Scripts/API_Notes/main_md2confluence_allfiles.py delete mode 100644 Scripts/API_Notes/markdown_conv.py create mode 100644 Scripts/API_Notes/md2conf_testdebug.py create mode 100644 Scripts/G2_Unenroll/skuid_lp.py create mode 100644 Scripts/Skuid_LPs/.DS_Store create mode 100644 Scripts/Skuid_LPs/find_completed.py create mode 100644 Scripts/Skuid_LPs/skuid_05lp.csv diff --git a/CustomerNotes/Artera.md b/CustomerNotes/Artera.md new file mode 100644 index 00000000..5c5ad32c --- /dev/null +++ b/CustomerNotes/Artera.md @@ -0,0 +1,17 @@ +## 11/21/2022 +### Meeting with Emily, new Lead +Jackie is the main teammate in Northpass. Emily has questions about our relationship with Northpass, etc. +Used to be a thought industry user - she loved them +Bi monthly meetings - starting in January - Emily, Jackie, Sally (Optional) +Which days are best? Wed/Thursday +Partnership team +Other questions and known issues: +* What product plan do they have? +TODO: Change Jackie the owner to schools. Add Emily and Sally to distribution list. +Jackie is the goto! Emily & Customer Education is the main use case. +Issues other people were having: +TODO: * The comms was not updating. Specifically, an image. There is a ticket from there. November 3rd a ticket was sent. They need an update by Dec 15th. +TODO: * Auto activation with learners is not working. Fake user - Jackie Arthur, jarthur+25@wellapp.com is the fake users name. + +Post-Meeting Notes: +* They have four instances: Meditech, LearnWELL, GrowWELL, WELL Health Partners diff --git a/CustomerNotes/Crayon.md b/CustomerNotes/Crayon.md index 19847945..2fc38b03 100644 --- a/CustomerNotes/Crayon.md +++ b/CustomerNotes/Crayon.md @@ -35,7 +35,7 @@ How it is currently setup: - Hubspot form on website, someone fills out the form - Form fills associated with campaign in Salesforce - In SFDC, he only gets when someone is registered for a course, no completed - - Campaign structure is based on course name + - Campaign structure is based on course [name](2022-11-21_name.md) Registration page - embed a hubspot form? Hubspot is just for marketing diff --git a/CustomerNotes/Skuid.md b/CustomerNotes/Skuid.md index 5d51659b..0007d0cf 100644 --- a/CustomerNotes/Skuid.md +++ b/CustomerNotes/Skuid.md @@ -69,3 +69,11 @@ Ideally, two or three fields will be setup to talk to Hubspot, each one is for v * TBD on if that group should be deleted *Appcues for Austin* - Austin needs to check in. + +## 11/22/2022 +### Appcues, Analytics & Learning Paths, Hubspot Opt-out Button +* Alexa asked about Quizzes and Surveys in Northpass and who integrates well. +* Wants to survey people both in and out of Skuid Skool. Sometimes the link will be in and out of the LMS. +* They also want to quiz and have more question and answer types - hotspot, for instance. I also let her know about matching in dynamic quizzes. +* Last requirement: multiple scheduling feature. A doodle type feature _in_ the survey. +* Their live trainings are scheduled via a consulting firm. So they are balancing multiple people's calendars. The consultants calendars are in the survey. Learners taking the survey. diff --git a/CustomerNotes/Talkspace.md b/CustomerNotes/Talkspace.md index 27cf20e6..b317383e 100644 --- a/CustomerNotes/Talkspace.md +++ b/CustomerNotes/Talkspace.md @@ -170,3 +170,10 @@ Molly and Taylor want more control of the process. They are trying to remove Fou 1. People attest that they are seeing clients 2. Get Access to Compliance Courses + +## 11/22/2022 +### Weekly Sync +Angel/Jenna meeting with Integrations person. Follow up next week. +TODO: Schedule Brainstorming session with Molly and Taylor for automating the Fountain > Compliance Courses. +Amanda: Course setup as linear, Course example: B2B Introduction to B2B. +TODO: Schedule meeting week of 12th with Amanda. Email beforehand with homework to bring some automation ideas & systems they want to connect to. diff --git a/Scripts/API_Notes/SampleNotes/Flink.md b/Scripts/API_Notes/SampleNotes/Flink.md index 48c33b26..6c018d86 100644 --- a/Scripts/API_Notes/SampleNotes/Flink.md +++ b/Scripts/API_Notes/SampleNotes/Flink.md @@ -42,166 +42,8 @@ Advised to start at the highest level and most broad groups, then add people to Figma file questions They need more training and enablement They will follow up for Figma files and setting those up for design -## 07/07/2022 -* MCA COLUMN ORDER: - * School ID - * Learner Name - * Email - * SSO UID - * Groups - * Course Name - * Course Version - * Enrollment Day - * Attempt STart - * Attempt End - * Attempt Number - * Course Progress - * Last Activity - * Last Activity Date - -Align on points of contact -Concerns? They are the main contact for all back end structure and content -Some teams - Simon's team for example - are country managers, such as Netherlands -Workload balance - should someone else be working with Simon? -Patrycja for urgent things? Can Anna keep working with Patrycja - -Simon's requests are not a priority sometimes -Flink needs to align with the market and some concerns are not right now -Priority right now is revamping everything in Northpass -Camila and Soner are main POCs for *everything* within Northpass - -AGENDA FOR EACH WEEKLY MEETING - align that the markets priorities and requests are actuall priorities - -Canva Demo -Logic for beginner, if you complete half of the must haves, you're at level X -All within northpass courses -Rider APP > open mobile app -If desktop > go to a URL - -Can we setup a login of button groups? -Course Scripts : a need/vision, they want to read transcript of courses -Can we add duration on course card within LP overview page? - -Events are a new push - - Talks from Hub Managers - - Already fruitful for netherlands - - Will be used by other markets - - Main district (Germany) were not involved in the events originally, and now they will be aligning on strategy - - - -Analytics, need hub based metrics to give to the managers - -Soner - one of the priorities are the reports he asked for -** Quiz hiding the score: ** - - If it is too hard, don't worry - - This is a one-time case - - Not super high priorty - - Doesn't make sense to push for this right now - -Front end layout - let them know what is possible -Next steps is categories, groups, and labels -They need to clean these labels, make them easier to understand -Filter by certain category labels i.e Marketing courses, etc - -HM = Hub Manager -IA = Inventory Associate - -Hub manager should any analytical view of the rest of the countries roles, aka they should be a manager in Northpass -From a learning perspective, there are no sub groups, HMs dont take Shift Lead Courses - -They should then filter by -Two main labels for learning, Market Label & Language Label -They need it to be cleaner for the backend -People should be able to see multiple languages - -There are multiple flows - HQ Cascade Content & HQ Diverse Content -Soner's suggestion, Each course is a contact in your phone and then you add different fields, so must have is just a label or category or ribbon -The most important thing is a clean view to see what their first/must complete courses are -All courses exist within this Matrix of circle courses -Eventually, they want hub managers to have a clean view of their employees, aka their hub -SAP is the goal for single source of truth for data -Zapier, Quinyx, BambooHR, -Okta is coming for SSO for access - -_Overall Deadline_ -Everything before Q4, SSO, Frontend -Context, they want to have everything setup in Northpass by Q4 because they are working on sustainability titles and their launch can be really clean in Q4. - -Single Course Analysis - because they wanted a dashboard -Course Completion - because they wanted to see who completed it - * Course completion NO should show up regardless of attempt start - -## 07/26/2022 - -Training and Content Team for Netherlands, Switzerland, Austria -2nd biggest market with 65 hubspot. German is the biggest with 100+. -Distribution/Hub manager for Netherlands -Has some bottle necks: - - MCA and 5000 entries - - Learning Path Analysis - -They manage everything from a google sheet -Hub managers have access to this google sheet -Currently manually sending emails and follow ups - NP communications are weak -Looker account within Flink, how can we get the data into Looker? (Upsell a Secure Data Transfer) -Scheduled Delivery would be great too -This would be useless if the the values (of location) are not in there. Can we do a scheduled delivery of an analytic with property filtered -Source of truth is Big Query or Looker for the country manager and job title (HUB) -Can we API into the properties? -Wants weekly analytics - - -Other Hot topics in the Netherlands: - - Frustrations with ILTs - - People can register for multiple sessions within an event (they shouldn't be able to) - - Can we prevent them from multiple sessions? - - Simon doesn't have the admin possiblity to unregister people from sessions - - He wants to register and unregister people - - If Simon increases the number of seats, that person can't re-register because they have already been denied - - Waiting list isn't good because a denial is a forever denial - - Needs to create a custom notification for a confirmation. They have a confirmation that they have booked, but no confirmation of the dates, link, time etc. - - In order for the people to get this on their agenda, they have to click add to calendar, it should be doing it automatically (this is what other LMS do) - - Very frustrated with the manual work, so much so that they aren't going to use it at all anymore. Just using it on a calendar invite on their own. - - Don't like that you need multiple courses per language. - - Quizzes: needing multiple quiz for every language. - -## 08/11/2022 - -* Reporting - * They are combining course a, b, and c into a new course A -OPPOSITE - * If course a is complete, then new courses a, b, and c need to be completed - * So everyone who has already completed those courses needs to be marked as complete in course A - * How can we mark someone as complete? - * People should be enrolled in the new course -* Courses - * number of enrollments - * Ask soner -* Needs info on events -* Upcoming on the global level - -## 09/22/2022 -* Banner Width smaller -* Mobile view search bar becomes too short - Phone view -* Chevron Carousel is okay for many courses -* Embed our Workforce Contact - * If you click contact, it will send them to a website hosted by Flink -* Soner to send brand guidelines & which buttons should be removed from collapsible menu -* Questions about Preview as Manager vs Learner -* Allow them to update FAQ on their own -* collapsible menu not showing in mobile - -## 10/06/2022 -* Cami and Soner to pull their own analytics -* Unsure what those key metrics are -* However, they currently look at: - * Completion % of courses - * Number of completed courses -* Planning needs to happen about what those analytics are -* Main priorities, cateogries, ensure the front end is "Flinky", -* Reduce banner slightly, Cami to send a picture of what she wants -* They want to launch ASAP, but need to find a window that works best -* Wednesdays are generally slow and could be a good transfer day -* Wednesday 10/19 - tentative +THIS IS NEW TEXT AS A TEST!!!! ## 10/13/2022 * Soner to work on communications plan and roll out diff --git a/Scripts/API_Notes/conf_functionsonly.py b/Scripts/API_Notes/conf_functionsonly.py index 3de51411..cdb1169d 100644 --- a/Scripts/API_Notes/conf_functionsonly.py +++ b/Scripts/API_Notes/conf_functionsonly.py @@ -1,14 +1,8 @@ -import io from datetime import date import markdown -from re import search import re -# import pypandoc and/or panflute rootdir = "/Users/normrasmussen/Documents/Northpass/Scripts/API_Notes/SampleNotes/" -#meetingstart = "##" -#meetingend = "##" -#rx = r'{}.*?{}'.format(re.escape(meetingstart), re.escape(meetingend)) def findheadings(): headingsarray = [] @@ -21,25 +15,40 @@ def findheadings(): # From StackOverflow: def noteSections(rootdir): - today = date.today() - today = today.strftime("%m/%d/%Y") - dateregex = "^[0-9]{1,2}\\/[0-9]{1,2}\\/[0-9]{4}$" + #today = date.today() + #today = today.strftime("%m/%d/%Y") + #dateregex = "^[0-9]{1,2}\\/[0-9]{1,2}\\/[0-9]{4}$" with open(rootdir+"Flink.md", "r") as f: notes_flag = False notes = '' for line in f: - if line.startswith(f"## {today}"): + if line.startswith("## "): notes_flag = True elif notes_flag: notes += line if not line.strip(): break - mdConvert(rootdir, notes) + print(notes) + # mdConvert(rootdir, notes) + +def meetingSections(rootdir): + dateregex = "^[0-9]{1,2}\\/[0-9]{1,2}\\/[0-9]{4}$" + currentnote = rootdir + "Flink.md" + with open(currentnote, "r") as f: + text = f.read() + #print(text) + #m = re.search(f"##(.^[0-9]{1,2}\\/[0-9]{1,2}\\/[0-9]{4}$)\n(.*)\n\n") + #m = re.search("##"+dateregex+"(.*)"+"##"+dateregex, text) + if m: + print("Found a section!") + found = m.group(1) + print(found) def mdConvert(rootdir, notes): conversion = markdown.markdown(notes) - print(notes) + print(conversion) # Add Conversion variable to payload for hubspot. Copy functions from the other files. if __name__ == "__main__": - noteSections(rootdir) + meetingSections(rootdir) + #noteSections(rootdir) diff --git a/Scripts/API_Notes/main_md2confluence.py b/Scripts/API_Notes/main_md2confluence.py new file mode 100644 index 00000000..7c4fbd56 --- /dev/null +++ b/Scripts/API_Notes/main_md2confluence.py @@ -0,0 +1,118 @@ +import markdown +import requests +from requests.auth import HTTPBasicAuth +import json +import sys + +input = sys.argv[1] +company = input.split("/")[6] + +def readFile(company): + rootdir = "/Users/normrasmussen/Documents/Northpass/Scripts/API_Notes/SampleNotes/" + with open(rootdir+company+".md", "r") as companyfile: + notes = companyfile.read() + notes = markdown.markdown(notes) + getContent(company, notes) + +def createNewPage(company, notes): + url = "https://northpass.atlassian.net/wiki/rest/api/content/" + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "X-Atlassian-Token": "no-check", + "Accept": "application/json", + "Content-Type": "application/json" + } + payload = json.dumps( { + "type":"page", + "title": company, + "ancestors":[{"id":2210463745}], + "space": + {"key":"~350535240"}, + "body": + {"storage": + {"value": notes, + "representation":"storage"}} + } ) + response = requests.request( + "POST", + url, + data=payload, + headers=headers, + auth=auth + ) + #print("createNewPage function has run") + response = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")) + #print(response) + exists = "already exists" + # This if statement checks if the response from the call includes that the page already exists. + # If the page does exist, it will get the ID and Version of the page and then run a PUT call to update the page. + if exists in response: + #print("This page exists! Updating page instead.") + getContent(company, notes) + +def getContent(company, notes): + url = "https://northpass.atlassian.net/wiki/rest/api/content/search?cql=parent=2210463745&expand=body.storage,version" + # Found the answer to this URL here: https://community.atlassian.com/t5/Confluence-questions/How-can-i-get-the-page-version-using-a-specific-page-id/qaq-p/898721 + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "Accept": "application/json", + } + response = requests.request("GET", url, headers=headers, auth=auth) + jsonResponse = response.json() + text = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",",": ")) + #print(text) + listCompanies = [] + for response in jsonResponse['results']: + if response['title'] == company: + #print(f"{company} Found.") + version = int(response["version"]["_links"]["self"][-1]) + if version == "": + version = 1 + else: + pass + id = response['id'] + #print(id) + #print(version) + updatePage(company, notes, id, version) + else: + listCompanies.append(response["title"]) + pass + #print("Other Companies, not pertinent right now. List of companies:") + #print(listCompanies) + +def updatePage(company, notes, id, version): + url = f"https://northpass.atlassian.net/wiki/rest/api/content/{id}" + newVersion = version+1 + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "X-Atlassian-Token": "no-check", + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent" : "python-requests/2.28.1", + } + payload = json.dumps( { + "version": { + "number": newVersion + }, + "type":"page", + "title": company, + "status": "curent", + "ancestors":[{"id": 2210463745}], + "body": + {"storage": + {"value": notes, + "representation":"storage"}} + } ) + response = requests.request( + "PUT", + url, + data=payload, + headers=headers, + auth=auth + ) + response = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")) + #print(response) + #print("updatePage function has run") + +if __name__ == "__main__": + readFile(company) diff --git a/Scripts/API_Notes/main_md2confluence_allfiles.py b/Scripts/API_Notes/main_md2confluence_allfiles.py new file mode 100644 index 00000000..1f79571c --- /dev/null +++ b/Scripts/API_Notes/main_md2confluence_allfiles.py @@ -0,0 +1,127 @@ +import markdown +import requests +from requests.auth import HTTPBasicAuth +import json +import os + +def findCompanies(): + rootdir = "/Users/normrasmussen/Documents/Northpass/CustomerNotes/" + files = os.listdir(rootdir) + for fileName in files: + if fileName.startswith(".") or fileName.startswith("ima"): + pass + else: + company = fileName[:-3] + #print(company) + readFile(company) + +def readFile(company): + rootdir = "/Users/normrasmussen/Documents/Northpass/CustomerNotes/" + with open(rootdir+company+".md", "r") as companyfile: + notes = companyfile.read() + notes = markdown.markdown(notes) + createNewPage(company, notes) + +def createNewPage(company, notes): + url = "https://northpass.atlassian.net/wiki/rest/api/content/" + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "X-Atlassian-Token": "no-check", + "Accept": "application/json", + "Content-Type": "application/json" + } + payload = json.dumps( { + "type":"page", + "title": company, + "ancestors":[{"id":2210463745}], + "space": + {"key":"~350535240"}, + "body": + {"storage": + {"value": notes, + "representation":"storage"}} + } ) + response = requests.request( + "POST", + url, + data=payload, + headers=headers, + auth=auth + ) + #print("createNewPage function has run") + response = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")) + #print(response) + exists = "already exists" + # This if statement checks if the response from the call includes that the page already exists. + # If the page does exist, it will get the ID and Version of the page and then run a PUT call to update the page. + if exists in response: + #print("This page exists! Updating page instead.") + getContent(company, notes) + +def getContent(company, notes): + url = "https://northpass.atlassian.net/wiki/rest/api/content/search?cql=parent=2210463745&expand=body.storage,version" + # Found the answer to this URL here: https://community.atlassian.com/t5/Confluence-questions/How-can-i-get-the-page-version-using-a-specific-page-id/qaq-p/898721 + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "Accept": "application/json", + } + response = requests.request("GET", url, headers=headers, auth=auth) + jsonResponse = response.json() + #print(jsonResponse['']) + text = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",",": ")) + print(text) + listCompanies = [] + for response in jsonResponse['results']: + if response['title'] == company: + #print(f"{company} Found.") + version = int(response["version"]["_links"]["self"][-1]) + if version == "": + version = 1 + else: + pass + id = response['id'] + #print(id) + #print(version) + updatePage(company, notes, id, version) + else: + listCompanies.append(response["title"]) + pass + #print("Other Companies, not pertinent right now. List of companies:") + #print(listCompanies) + +def updatePage(company, notes, id, version): + url = f"https://northpass.atlassian.net/wiki/rest/api/content/{id}" + newVersion = version+1 + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "X-Atlassian-Token": "no-check", + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent" : "python-requests/2.28.1", + } + payload = json.dumps( { + "version": { + "number": newVersion + }, + "type":"page", + "title": company, + "status": "curent", + "ancestors":[{"id": 2210463745}], + "body": + {"storage": + {"value": notes, + "representation":"storage"}} + } ) + response = requests.request( + "PUT", + url, + data=payload, + headers=headers, + auth=auth + ) + response = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")) + #print(response) + #print("updatePage function has run") + +if __name__ == "__main__": + findCompanies() diff --git a/Scripts/API_Notes/markdown_conv.py b/Scripts/API_Notes/markdown_conv.py deleted file mode 100644 index 1f9d92da..00000000 --- a/Scripts/API_Notes/markdown_conv.py +++ /dev/null @@ -1,50 +0,0 @@ -import markdown -import requests -from requests.auth import HTTPBasicAuth -import json -import os - -def readFile(company): - rootdir = "/Users/normrasmussen/Documents/Northpass/CustomerNotes/" - with open(rootdir+company+".md", "r") as companyfile: - notes = companyfile.read() - conversion = markdown.markdown(notes) - createNewPage(company, conversion) - - -def createNewPage(company, notes): - url = "https://northpass.atlassian.net/wiki/rest/api/content/" - auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") - headers = { - "X-Atlassian-Token": "no-check", - "Accept": "application/json", - "Content-Type": "application/json" - } - payload = json.dumps( { - "type":"page", - "title": company, - "ancestors":[{"id":2210463745}], - "space": - {"key":"~350535240"}, - "body": - {"storage": - {"value": notes, - "representation":"storage"}} - } ) - - response = requests.request( - "POST", - url, - data=payload, - headers=headers, - auth=auth - ) - print("createNewPage function has run") - response = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")) - print(response) - #jsonResponse = response.json() - #print(jsonResponse) - -if __name__ == "__main__": - readFile(company="Flink") - #readNewNotes(company="Flink") diff --git a/Scripts/API_Notes/md2conf_testdebug.py b/Scripts/API_Notes/md2conf_testdebug.py new file mode 100644 index 00000000..da87ab0e --- /dev/null +++ b/Scripts/API_Notes/md2conf_testdebug.py @@ -0,0 +1,116 @@ +import markdown +import requests +from requests.auth import HTTPBasicAuth +import json + +def readFile(company): + rootdir = "/Users/normrasmussen/Documents/Northpass/Scripts/API_Notes/SampleNotes/" + with open(rootdir+company+".md", "r") as companyfile: + notes = companyfile.read() + notes = markdown.markdown(notes) + getContent(company, notes) + +def createNewPage(company, notes): + url = "https://northpass.atlassian.net/wiki/rest/api/content/" + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "X-Atlassian-Token": "no-check", + "Accept": "application/json", + "Content-Type": "application/json" + } + payload = json.dumps( { + "type":"page", + "title": company, + "ancestors":[{"id":2210463745}], + "space": + {"key":"~350535240"}, + "body": + {"storage": + {"value": notes, + "representation":"storage"}} + } ) + response = requests.request( + "POST", + url, + data=payload, + headers=headers, + auth=auth + ) + print("createNewPage function has run") + response = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")) + print(response) + exists = "already exists" + if exists in response: + print("This page exists! Updating page instead.") + getContent(company, notes) + +def getContent(company, notes): + url = "https://northpass.atlassian.net/wiki/rest/api/content/search?cql=parent=2210463745&expand=body.storage,version" + # Found the answer to this URL here: https://community.atlassian.com/t5/Confluence-questions/How-can-i-get-the-page-version-using-a-specific-page-id/qaq-p/898721 + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "Accept": "application/json", + } + response = requests.request("GET", url, headers=headers, auth=auth) + jsonResponse = response.json() + + text = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",",": ")) + print(text) + listCompanies = [] + for response in jsonResponse['results']: + if response['title'] == company: + print(f"{company} Found.") + version = int(response["version"]["_links"]["self"][-1]) + if version == "": + version = 1 + else: + pass + id = response['id'] + print(id) + print(version) + updatePage(company, notes, id, version) + else: + listCompanies.append(response["title"]) + pass + print("Other Companies, not pertinent right now. List of companies:") + print(listCompanies) + +def updatePage(company, notes, id, version): + url = f"https://northpass.atlassian.net/wiki/rest/api/content/{id}" + newVersion = version+1 + print(newVersion) + auth = HTTPBasicAuth("nrasmussen@northpass.com", "qf9Il7X4wkthgQKBOIly5737") + headers = { + "X-Atlassian-Token": "no-check", + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent" : "python-requests/2.28.1", + } + payload = json.dumps( { + "version": { + "number": newVersion + }, + "type":"page", + "title": company, + "status": "curent", + "ancestors":[{"id": 2210463745}], + "body": + {"storage": + {"value": notes, + "representation":"storage"}} + } ) + + response = requests.request( + "PUT", + url, + data=payload, + headers=headers, + auth=auth + ) + response = json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": ")) + print(response) + print("updatePage function has run") + +if __name__ == "__main__": + readFile(company="Flink") + #readNewNotes(company="Flink") diff --git a/Scripts/G2_Unenroll/fix_unenroll.py b/Scripts/G2_Unenroll/fix_unenroll.py index 1b78611f..f48117cf 100644 --- a/Scripts/G2_Unenroll/fix_unenroll.py +++ b/Scripts/G2_Unenroll/fix_unenroll.py @@ -1,81 +1,28 @@ -import requests from collections import Counter import pandas as pd -basecsv = "/Users/normrasmussen/Documents/Northpass/Scripts/G2_Unenroll/g2mca_112122.csv" -apiKey = "JRDpCGQ7vSRiva6t5OkWDr5eJ" #G2 +basecsv = "/Users/normrasmussen/Documents/Northpass/Scripts/G2_Unenroll/skuid_05lp.csv" -def mainFunc(basecsv, apiKey): +def mainFunc(basecsv): readData = pd.read_csv( basecsv, index_col=False, ) - readData.loc[readData['Course Name'].isin([ - 'G2 Profile Anatomy', 'Profile Performance & Lead Management', - 'Review Tracking & Brand Building', 'The Review Rundown'])] - extractedList = readData.loc[readData['Attempt Start'].isnull(),'Email'].tolist() - fourOccs = Counter(extractedList) - finalNames = [] - for name, occurences in fourOccs.items(): - if occurences == 4: - finalNames.append(name) - findUuids(finalNames, readData, apiKey) + parsedData = readData.drop_duplicates(subset='Course_Name', keep="first") + if parsedData.loc[readData['Course Name'].isin([ + 'Get Started with Models - Level 1', + 'Configure Model Fields - Level 1', + 'Configure Model Conditions - Level 1', + 'Configure Model Actions - Level 1', + 'Manage Models - Level 1', + 'Intro to UI Only Fields - Level 1'])]: + extractedList = readData.loc[readData['Email'].tolist() + fourOccs = Counter(extractedList) + finalNames = [] + for name, occurences in fourOccs.items(): + if occurences == 6: + finalNames.append(name) -def findUuids(finalNames, readData, apiKey): - emailUuid = [] - uuidList = [] - deactivateUuid = {} - try: - for name in finalNames: - baseUrlname = "https://api.northpass.com/v2/people?filter[email][eq]=" - name = name - url = baseUrlname + f"{name}" - headers = { - "accept": "*/*", - "x-api-key": apiKey, - "content-type": "application/json", - } - response = requests.get(url, headers=headers) - response = response.json() - uuid = response["data"][0]["id"] - uuidList.append(uuid) - deactivateUuid.update({name: uuid}) - emailUuid.append(deactivateUuid) - except: - print("An error occured") - finally: - print(deactivateUuid) - removeFromGroup(uuidList, apiKey) - -def removeFromGroup(uuidList, apiKey): - numRemoved = 0 - badUuid = [] - for uuid in uuidList: - uuidList = [] - url = f"https://api.northpass.com/v2/people/{uuid}/relationships/groups" - headers = { - "accept": "application/json", - "content-type": "application/json", - "X-Api-Key": apiKey - } - payload = {"data": [ - { - "id": "d78af2ad-a6c8-4016-90a4-fb00bcc67891", - "type": "membership-groups" - } - ]} - response = requests.delete(url, json=payload, headers=headers) - status = response.status_code - if response.status_code == 200: - print(f"UserID {uuid} okay to be deleted.") - numRemoved += 1 - uuidList.append(uuid) - else: - print(f"Some other error {status} for {uuid}") - badUuid.append(uuid) - print(f"Complete! {numRemoved} people removed from group.") - print("Bad UUIDS: ") - print(badUuid) if __name__ == "__main__": - mainFunc(basecsv, apiKey) + mainFunc(basecsv) diff --git a/Scripts/G2_Unenroll/skuid_lp.py b/Scripts/G2_Unenroll/skuid_lp.py new file mode 100644 index 00000000..6c1d06b3 --- /dev/null +++ b/Scripts/G2_Unenroll/skuid_lp.py @@ -0,0 +1,27 @@ +from collections import Counter +import pandas as pd + +basecsv = "/Users/normrasmussen/Documents/Northpass/Scripts/G2_Unenroll/skuid_05lp.csv" + +def mainFunc(basecsv): + readData = pd.read_csv( + basecsv, + index_col=False, + ) + parsedData = readData.drop_duplicates(subset='Course_Name', keep="first") + if parsedData.loc[readData['Course Name'].isin([ + 'Get Started with Models - Level 1', + 'Configure Model Fields - Level 1', + 'Configure Model Conditions - Level 1', + 'Configure Model Actions - Level 1', + 'Manage Models - Level 1', + 'Intro to UI Only Fields - Level 1'])]: + extractedList = readData.loc[readData['Email'].tolist() + fourOccs = Counter(extractedList) + finalNames = [] + for name, occurences in fourOccs.items(): + if occurences == 6: + finalNames.append(name) + +if __name__ == "__main__": + mainFunc(basecsv) diff --git a/Scripts/Skuid_LPs/.DS_Store b/Scripts/Skuid_LPs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 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 delta 1559 zcmZuxX-rl}6rFqDynXpZlmZ6*w1q&`XpMC%iin7@XmF{f5)-S|g{6Y{!@VH38mnb_ z!mt$3#=T0gSf?m12wIm0sSCK&28h;JV}-W1HKOf&G)?-WFL}wy%$>RSoO{n?W?Gr8 zW^NxjoDec3&l?5dN9OO2(gLtn7Apf?YkWW3Rl1b-~z8D@YC5NC=!23$B}d zU*}W&fLD&SP11+NNswXtIk%iK)++O!Cl#qV-8e~Vlcgh`rSQV-q@!ohQGdE zdrY_#pe3qj)ImxyOq0_Dp>+U!YBYvXAv8n?X+nW3lkmAtJwY&p$*u4^8{j{8{k9Opr11;m{br?vUAmW(=N5Cl`fb^8GDRgg7-Zw zUj0h#r+h3wmS@o8bbz!4J8&+Xhhd~bXt0paD8i$ZmzUuJbVDaF-WHDiRMzks7K|~p z=_H8k2d7DBy3@9;4D+TLV|-!s*0Z#q;kx>@IzZVfKb7Z0B)zC5(h*XbBx5q!FK$i+ zjXep)0=A$x7O_Wx$oQr(d;{3za4c~nWAoYNURVf(KkJR1Xn0bIAsQ_{HmVoy;2VQ* zgW_|5%hH#F%jr;j;du+QMM1TwnDo9NeA|h!_uD;5t+m#CWX^(zQiM@sgzBG4C*U2e z3v;wZbf$Vq9jWXhb)uw9mS%y@W?zOpmT?Ytu-`90u_do1R(E1w?zjdh2AM6q04`I{ zL!rPS!ZGYdBXs*QS6s7A7)WOsS71AzTL%rms_LPLwKYIKFF!Ao<+&H(6z~U^;V~Xd zK<-WJg=hU= zcn(Gd29uM-lj3~mjI|Hiy{%010Xb<-GfpsVCwkd?ZMczHE*9{ayKt%Q?w;tf75P}g zcexlydm8vmIH+7vHfZCVOWFS4nxPpHUJMf3- z>%POdi)9_c9R9&GoQG~#%swa)+l5?zfpx$KRHna-Yv(Gxv z7s z@EnE8DfAYdAblzI!>uCiM@*Eg^Taxg0O~{$$~T?GDVA@9a>Vv0ys;5SfRv)%?M|GG|p@6)YUZEqUozQMh6_dO|z2He=VXe45FM;yvRy?HsTd{8j K_?e$@y!