READ ME Last updated March 5 2023
Pauly is a hub for all things school-related.
Build by Andrew Mainella
Saint Paul's High School Student Council 2023-2024
Important
Functions repo can be found at https://github.com/Archimedes4/Pauly-Functions
Power by expo using expo router at its core. Application also uses redux for storage.
Pauly uses Microsoft graph and SharePoint lists as a database.
Microsoft Graph Permissions see Permissions
Note
If an endpoint appears both in regular and government mode. It will only be under the regular mode unless the methods are different. Different methods appear in government
Government
Youtube Iframe and data
Randrop api
| Endpoint | Methods | Referenece |
|---|---|---|
| https://api.raindrop.io/rest/v1/raindrops | GET | https://developer.raindrop.io/ |
Pauly Functions See in functions
Important
The public folder needs pdfjs to run and the code in components -> pdf -> index.web needs to be updated.
- tests: Holds tests
- assets: Holds images and fonts
- public: Holds manifest, well-known and pdfjs to remove a need for a cdn.
- src: holds apps code
- app: file structure for expo router
- components: rendered functions that aren;t a page.
- hooks: hooks
- redux: storage reducers and actions
- utils: functions that aren't rendered
- constants: holds types, colors, and some constants
- rest: config files env files readme
Some things were needed in order to get things working without errors. Here is a list of them please check that these patches are actually needed.
- React Native Reanimated Expo is compatable with React Native Reanimated 3.3.
Error: requestAnimationFrame is not defined
Issue: expo/router#718 Patch: https://gist.github.com/javascripter/4e4e20e9024a33592437648b718c763d
- Expo Fonts Expo fonts and React Native Paper aren't playing nice. Taking over the 3 second threshold to load.
Issue: expo/expo#12382 Patch: Inside Issue very simple chaning the timout
Reference https://learn.microsoft.com/en-us/graph/permissions-reference
Why Consent Is Needed https://learn.microsoft.com/en-us/graph/api/resources/consentrequests-overview?view=graph-rest-1.0
All permissions are Delegated permissions
| Permission | Admin Consent Required | Description |
|---|---|---|
| User.ReadWrite | NO | Allows the app to read your profile. It also allows the app to update your profile information on your behalf. |
| User.ReadBasic.All | NO | Allows the app to read a basic set of profile properties of other users in your organization on behalf of the signed-in user. This includes display name, first and last name, email address, open extensions and photo. Also allows the app to read the full profile of the signed-in user. |
| ChannelMessage.Read.All | YES | Allows an app to read a channel's messages in Microsoft Teams, on behalf of the signed-in user. |
| Channel.ReadBasic.All | NO | Read channel names and channel descriptions, on behalf of the signed-in user. |
| Calendars.ReadWrite | YES | Allows the app to create, read, update, and delete events in user calendars. |
| Team.ReadBasic.All | NO | Read the names and descriptions of teams, on behalf of the signed-in user. |
| Sites.Read.All | NO | Allows the app to read documents and list items in all site collections on behalf of the signed-in user. |
| Group.ReadWrite.All | YES | Allows the app to create groups and read all group properties and memberships on behalf of the signed-in user. Also allows the app to read and write calendar, conversations, files, and other group content for all groups the signed-in user can access. Additionally allows group owners to manage their groups and allows group members to update group content. |
This also has the regular permissions these are just extra.
| Permission | Admin Consent Required | Description |
|---|---|---|
| Application.ReadWrite.All | YES | Allows the app to create, read, update and delete applications and service principals on behalf of the signed-in user. |
| Sites.Manage.All | YES | Allows the app to manage and create lists, documents, and list items in all site collections on behalf of the signed-in user. |
| TeamMember.Read.All | YES | Read the members of teams, on behalf of the signed-in user. |
| TeamSettings.ReadWrite.All | YES | Read and change all teams' settings, on behalf of the signed-in user. |
SubmitCommission - Used to generate a valid commission submission. Because users cannot write to Pauly the function firsts validates the commissions submission and adds data like the date. Doing all this with the users credentials. Then users an application adds the submission.
SyncCalendarOrchestator - A durable function composed of activities that sync a iCalendar with Paulys Calendar. The function is mostly idempotent and uses apis that have the same output no matter when called.
Known limitations:
- For loops, find and some are used throught the code. Therefore, if many thousands of events were to be tracked the function would fail.
- As for being idempotent, if the function was called many times at once and had to create events, the function would create multiple events. This is because the function looks for events that exist and then creates them, but all the orchestrates would have calculated that an event needs to be created and therefore would create events. As long as the orcestrator is not spammed and called many times while other orcestrations are running it will work. It also does not matter when azure decideds to run the function, if the function is run well after it is called it still works. The only limitation in that regard is the token expiering and therefore, the function would fail and could be run again without issue.
The calendar is organized into documents of years containing collections of months. These months are formatted as a number based on January being 1. Inside each collection documents of days are inside. Each day contains the day, month, and year. As well as the school day and schedule id. If the schedule does not have a value it is schedule one (default schedule).
Commissions are organized into documents that are named with their commission id. In each document, there is a
- Start date
- End date
- Hidden
- Points (what the commission is worth)
- Selected Page (which page is shown)
- Value (the type of commission it is)
- Approved by issuer
- Location
- Image
- Image and Location
- QR Code
The notifcations page has a board, a message, insigts (used and trending) and tasks. The tasks are from microsoft graph using the todo api. The insights are from microsoft graph the.
Refrences
TODO: https://learn.microsoft.com/en-us/graph/api/resources/todo-overview?view=graph-rest-1.0
Insights (used, trending): https://learn.microsoft.com/en-us/graph/api/resources/officegraphinsights?view=graph-rest-1.0
Board: https://learn.microsoft.com/en-us/graph/api/driveitem-get-content-format?view=graph-rest-1.0&tabs=http
The resource page takes teams posts and displays them. It has access to files and sections. Resource has a news section powered by the wordpress api. Resources has a scholarship database powered by the raindrop api.
This is the sports page that shows sport highlights and has team rosters. The sports page has embeded youtube videos from the Saint Paul's High School youtube page. It also as videos and images uploaded through government.
| Name | Value |
|---|---|
| white | #ffffff |
| light gray | #ededed |
| dark gray | #444444 |
| maroon | #793033 |
| warning orange | #FF6700 |
| blue gray | #6699CC |
NOTE Extensions are automatically setup in the initialization process
{
id: 'paulyClass',
description: 'Pauly Class Data',
targetTypes: ['Group'],
owner: CLIENT_ID,
properties: [
{
name: 'className', // This property will be optional in the future
type: 'String',
},
{
name: 'schoolYearEventId',
type: 'String',
},
{
name: 'semesterId',
type: 'String',
},
{
name: 'roomId',
type: 'String',
},
{
name: 'periodData',
type: 'String', // An Array as long as the number of days in the cycle
},
{
name: 'homeroom',
type: 'Boolean'
}
],
}
| Dependency | Main Version | Reason |
|---|---|---|
| @azure/msal-browser | 2 | Core auth api for web |
| @azure/msal-react | 1 | Core auth api for web |
| @expo/config-plugins | 7 | |
| @react-google-maps/api | 2 | |
| @react-native-async-storage/async-storage | 1 | |
| @react-native-community/slider | 4 | |
| @reduxjs/toolkit | 1 | |
| @types/node" | 20 | |
| @types/pdfjs-dist | 2 | |
| @types/react | 18 | |
| expo | sdk 50 | Core api |
| expo-auth-session | 5 | Core auth api for native |
| expo-av | 13 | |
| expo-build-properties | 0 | |
| expo-clipboard | 5 | |
| expo-constants | 15 | |
| expo-crypto | 12 | |
| expo-dev-client | 3 | Dev cliant for testing without the use of expo go |
| expo-font | 11 | Used to load fonts into the application |
| expo-image | 1 | |
| expo-image-picker | 14 | |
| expo-linking | 6 | |
| expo-location | 16 | Used to get location in commissions |
| expo-network | 5 | Used to make such connection is avaliable |
| expo-print | 12 | Used in commissions to print QR code |
| expo-router | 3 | Holds navigations and linking for the project |
| expo-splash-screen | 0.26 | |
| expo-status-bar | 1 | |
| expo-web-browser | 12 | |
| geolib | 3 | used to calculated distance in commission |
| metro | 0 | |
| patch-package | 8 | Used to fix some of the intricisies with the packages the reasons for which are documenent in the oddities section |
| pdfjs-dist | 3 | |
| postinstall-postinstall | 2 | |
| react | 18 | Core api for the project |
| react-art | 18 | |
| react-dom | 18 | A peer dependancy for expo router |
| react-native | 73 | Core api for the project |
| react-native-gesture-handler | 2 | gesuture handler used as a peer depency and in places such as home view. |
| react-native-maps | 1 | Used in government commission comonent for native apps |
| react-native-paper | 5 | Needed for react-native-paper-dates |
| react-native-paper-dates | 0 | Main components used to set time. |
| react-native-qrcode-svg | 6 | |
| react-native-reanimated | 3 | |
| react-native-safe-area-context | 4 | |
| react-native-screens | 3 | |
| react-native-svg | 14 | used for svgs, svgs can be found in src -> components -> icons |
| react-native-vector-icons | 10 | |
| react-native-webview | 13 | |
| react-quill | 2 | |
| react-redux | 8 | Core store api |
| react-refresh | 0 | |
| react-router-native | 6 | |
| react-test-renderer | 18 | |
| reanimated-color-picker | 3 | Used in schedules to pick the schedule color |
| redux | 4 | |
| typescript | 5 |
How to setup Pauly
Commands to setup Azure services
az login
https://learn.microsoft.com/en-us/cli/azure/ad/app?view=azure-cli-latest#az-ad-app-create
Save appId for use later
az ad app create --display-name Pauly
https://learn.microsoft.com/en-us/cli/azure/ad/signed-in-user?view=azure-cli-latest
Save userId for use later
az ad signed-in-user show
https://learn.microsoft.com/en-us/cli/azure/ad/app/owner?view=azure-cli-latest#az-ad-app-owner-add
az ad app owner add --id {appId} --owner-object-id {userId}
https://learn.microsoft.com/en-us/cli/azure/ad/app?view=azure-cli-latest#az-ad-app-update
update azure ad app
az rest --method patch --uri 'https://graph.microsoft.com/v1.0/applications/18e8faf2-1739-4895-80fa-3c8cf0b32fc6' --headers 'Content-Type=application/json' --body "{\"spa\":{\"redirectUris\":[\"http://localhost:19006/auth\",\"https://paulysphs.ca\",\"https://www.paulysphs.ca\"]},\"publicClient\":{\"redirectUris\":[\"Archimedes4.Pauly://auth\"]},\"signInAudience\":\"AzureADMyOrg\",\"api\":{\"oauth2PermissionScopes\":[{\"adminConsentDescription\":\"AllthescopesrequiredtoclaimcommissionsinPauly.Thisistoaccessthemainfunctionofthecommissionsapi.\",\"adminConsentDisplayName\":\"claimcommission\",\"id\":\"c62762bd-6568-4f5f-b9d5-eb0eae3882cf\",\"isEnabled\":true,\"type\":\"User\",\"userConsentDescription\":null,\"userConsentDisplayName\":null,\"value\":\"commissions\"}]}}"
https://learn.microsoft.com/en-us/azure/static-web-apps/get-started-cli?tabs=vanilla-javascript
Note: The resource group that you use will be tied to the web app. Some other resource group can be used but this method is preferable.
az group create \
--name Pauly-SWA \
--location "eastus2"
az staticwebapp create \
--name Pauly-Static-Web-App \
--resource-group Pauly-SWA \
--source https://github.com/Archimedes4/Pauly.git \
--location "eastus2" \
--branch master \
--app-location "/web-build" \
--output-location "build" \
--login-with-github
Upon creation of the static web app a workflow file will be created. There should only be one static web app workflow file, delete the old ones. Two the location should be changed to /dist
az storage account create --name paulystorage --resource-group Pauly-SWA
https://learn.microsoft.com/en-us/cli/azure/functionapp?view=azure-cli-latest#az-functionapp-create
az functionapp create --name Pauly-Functions --resource-group Pauly-SWA --storage-account paulystorage --consumption-plan-location eastus2 --runtime node --functions-version 4
https://learn.microsoft.com/en-us/cli/azure/functionapp/cors?view=azure-cli-latest
Note: http://localhost:19006 is for development purposes and can be removed.
az functionapp cors add -g Pauly-SWA -n Pauly-Functions --allowed-origins https://www.paulysphs.ca https://paulysphs.ca http://localhost:19006
https://learn.microsoft.com/en-us/cli/azure/functionapp/config/appsettings?view=azure-cli-latest#az-functionapp-config-appsettings-set
Replace the values in the command. To get the tenant id, client id and client secret go to portal.azure.com.
-Microsoft Entra Id -> App Registrations -> Pauly
Then copy the client Id and Tenant Id
Then navigate to Certificates & Secrets. Click "New Client Secret" the set the description to "Pauly Functions" or whatever. Press add and copy the newly created client secret and add it to this function.
az functionapp config appsettings set --name Pauly-Functions --resource-group Pauly-SWA --settings CLIENTID={ClientId goes here (remove brakets)} TENANTID={TenantId goes here} CLIENTSECRET={client secret goes here}
az functionapp deployment github-actions add --resource-group Pauly-SWA --repo "https://github.com/Archimedes4/Pauly-Functions" --name Pauly-Functions --login-with-github --build-path "/api"
Update function workflow env like:
env:
AZURE_FUNCTIONAPP_NAME: 'Pauly-Functions' # set this to your function app name on Azure
AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your function app project, defaults to the repository root
NODE_VERSION: '18.x' # set this to the node version to use (e.g. '8.x', '10.x', '12.x')
Login into pauly in government mode. Than go to governent -> graph -> groups. Look for Pauly, click on it can copy id. This is the org id for the group. Pauly has a config file named PaulyConfig which contains three values these values need to be apart of the main config file inorder for Pauly to work.
- tenant id
- Client ID (the ID of Paulys application)
- org id (the id of Pauly's group)
Go to the admin panel and initilize pauly. Code will break if Pauly is already initilized. If hard reseting Pauly delete Pauly group and Pauly extensions. This can all be done in the graph section of Government.
Once Pauly has been setup copy the group Id of pauly and set an environment variable ORGWIDEGROUPID as in Set Environment Variables. This is for the functions.
Give the application the Sties.Selected permission. \
Go to Azure then -> Microsoft Entra Id -> App Registrations -> Pauly -> Api Permissions
looks like:
Follow the images to add the permission.
go to https://developer.microsoft.com/en-us/graph/graph-explorer
get the site id
https://graph.microsoft.com/v1.0/groups/{orgId}/sites/root?$select=id
Give the permission Sites.FullControl.All to ms graph. Do not consent on behalf of organization.
set the method to POST and the url to
https://graph.microsoft.com/v1.0/sites/{siteId}/permissions
body
{
"roles": [
"write"
],
"grantedToIdentities": [
{
"application": {
"id": clientId,
"displayName": "Pauly"
}
}
]
}
Rotating client secrets after 160 days. Follow the steps in Set Environment Variables no need to change teant id and client id.
-
Add the widget as a target and copy the code from the widget.
-
Add https://github.com/AzureAD/microsoft-authentication-library-for-objc as a package dependancy.
-
Add the dependancy to both the widget and pauly. (The widget needs pauly to have the depndancy) This is added in the build face.
-
Add the keychain services entitlement (just to the widget) and add com.microsoft.adalcache.
-
Put the entitlements file in the proper folder and make sure the release and debug code signing point to it.
-
Set the widget marketing version the current short version of pauly (ex: 1.1.1). In build settings.
If a validate imbeded binary error is being given make sure the current project version above the marketing version matches Pauly. Consult app.config.js or error log to get the curent version.
If the Widget says please login but the user is logged in, double check the entitlments file.
-Working Commission Submissions -Live dashboard of scores and submissions for a commission. Using change notifications.
Know bugs to fix. -In the calendar don't allow the user to create a school year during existing school years. -In the calendar don't allow the user to create a school day during existing school days.