diff --git a/.github/workflows/updateContacts.yml b/.github/workflows/updateContacts.yml new file mode 100644 index 000000000..038320b05 --- /dev/null +++ b/.github/workflows/updateContacts.yml @@ -0,0 +1,19 @@ +name: Contact Email Update + +on: + schedule: + - cron: '0 0 31 1,7 *' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout Main repo + uses: actions/checkout@v2 + + - name: Contact Email Update + env: + API_KEY: ${{ secrets.NotifyAPIKey }} + TEMPLATE_ID: "" + run: ./assets/py/emailUpdateScript.py diff --git a/_data/spdx b/_data/spdx index ccb324e26..84fbef038 160000 --- a/_data/spdx +++ b/_data/spdx @@ -1 +1 @@ -Subproject commit ccb324e264bfa52263fd14993e5fe9058c616451 +Subproject commit 84fbef038f107016023da290f09dab989208fd8e diff --git a/assets/py/emailUpdateScript.py b/assets/py/emailUpdateScript.py new file mode 100755 index 000000000..cf01bdba6 --- /dev/null +++ b/assets/py/emailUpdateScript.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# This Python file uses the following encoding: utf-8 +import json, os +import urllib.request +from datetime import date, timedelta, datetime +from notifications_python_client.notifications import NotificationsAPIClient +############################################################################### +###From ore-ero folder, run with ./assets/py/emailUpdateScript.py ### +############################################################################### +#Maximum amount of days since last update, half a year default +maxDaysNoUpdate = 182 + +frTypes = {"code": "code", + "design": "design", + "software": "logiciel", + "standard": "norme", + "partnership": "partenariat"} + +formName = {"code": {"en": "open-source-code-form", "fr": "code-source-ouvert-formulaire"}, + "design": {"en": "open-design-form", "fr": "design-libre-formulaire"}, + "software": {"en": "open-source-software-form", "fr": "logiciel-libre-formulaire"}, + "standard": {"en": "open-standard-form", "fr": "norme-ouverte-formulaire"}, + "partnership": {"en": "partnership-form", "fr": "partenariat-formulaire"}} + + +def sendEmails(emailData): + client = NotificationsAPIClient(os.getenv("API_KEY"), "https://api.notification.alpha.canada.ca") + for data in emailData: + #Replace data[0] with any address to test the script + client.send_notification( + data[0], os.getenv("TEMPLATE_ID"), + {'EN_NAME': data[1], 'FR_NAME': data[2], 'LAST_UPDATED': data[3], + 'EN_TYPE': data[4], 'FR_TYPE': frTypes[data[4]], + 'EN_FORM': formName[data[4]]["en"], 'FR_FORM': formName[data[4]]["fr"]}) + + +def checkCodeEmails(): + codeDb = urllib.request.urlopen("https://code.open.canada.ca/code.json") + data = json.loads(codeDb.read()) + codeData = [] + if data is not None: + for level in data.values(): + for admin in level.values(): + for release in admin["releases"]: + if (datetime.strptime(release["date"]["metadataLastUpdated"], '%Y-%m-%d').date() + + timedelta(days=maxDaysNoUpdate) < date.today()): + if "noreply" not in release["contact"]["email"]: + codeData.append((release["contact"]["email"], release["name"]["en"], + release["name"]["fr"], release["date"]["metadataLastUpdated"], + "code")) + return codeData + + +def checkDesignEmails(): + designDb = urllib.request.urlopen("https://code.open.canada.ca/design.json") + data = json.loads(designDb.read()) + designData = [] + if data is not None: + for project in data.values(): + for administration in project["administrations"]: + for use in administration["uses"]: + if (datetime.strptime(use["date"]["metadataLastUpdated"], '%Y-%m-%d').date() + + timedelta(days=maxDaysNoUpdate) < date.today()): + if "noreply" not in use["contact"]["email"]: + designData.append((use["contact"]["email"], project["name"]["en"], + project["name"]["fr"], use["date"]["metadataLastUpdated"], + "design")) + return designData + +def checkSoftwareEmails(): + softwareDb = urllib.request.urlopen("https://code.open.canada.ca/software.json") + data = json.loads(softwareDb.read()) + softwareData = [] + if data is not None: + for project in data.values(): + for administration in project["administrations"]: + for use in administration["uses"]: + if (datetime.strptime(use["date"]["metadataLastUpdated"], '%Y-%m-%d').date() + + timedelta(days=maxDaysNoUpdate) < date.today()): + if "noreply" not in use["contact"]["email"]: + softwareData.append((use["contact"]["email"], project["name"]["en"], + project["name"]["fr"], use["date"]["metadataLastUpdated"], + "software")) + return softwareData + +def checkStandardEmails(): + standardDb = urllib.request.urlopen("https://code.open.canada.ca/standard.json") + data = json.loads(standardDb.read()) + standardData = [] + if data is not None: + for project in data.values(): + for administration in project["administrations"]: + if (datetime.strptime(administration["date"]["metadataLastUpdated"], '%Y-%m-%d').date() + + timedelta(days=maxDaysNoUpdate) < date.today()): + if "noreply" not in administration["contact"]["email"]: + standardData.append((administration["contact"]["email"], project["standardAcronym"], + project["standardAcronym"], administration["date"]["metadataLastUpdated"], + "standard")) + return standardData + +def checkPartnershipEmails(): + partnershipDb = urllib.request.urlopen("https://code.open.canada.ca/partnership.json") + data = json.loads(partnershipDb.read()) + partnershipData = [] + if data is not None: + for level in data.values(): + for admin in level.values(): + for project in admin["projects"]: + if (datetime.strptime(project["date"]["metadataLastUpdated"], '%Y-%m-%d').date() + + timedelta(days=maxDaysNoUpdate) < date.today()): + if "noreply" not in project["contact"]["email"]: + partnershipData.append((project["contact"]["email"], project["name"]["en"], + project["name"]["fr"], project["date"]["metadataLastUpdated"], + "partnership")) + return partnershipData + + +print("Started task at: " + datetime.now().isoformat(' ', 'seconds')) +sendEmails(checkCodeEmails() + checkDesignEmails() + checkSoftwareEmails() + + checkStandardEmails() + checkPartnershipEmails()) +print("Finished task at: " + datetime.now().isoformat(' ', 'seconds')) + diff --git a/assets/py/messageTemplates.py b/assets/py/messageTemplates.py new file mode 100644 index 000000000..ea49f64b5 --- /dev/null +++ b/assets/py/messageTemplates.py @@ -0,0 +1,30 @@ +class Templates: + ##This file can be erased once the template is setup on the Notify API + ##To have this template on the Notify API, replace {} with (()) + plain = """ + English Message: + + Automated message about {EN_NAME} on the ORE platform, last updated {LAST_UPDATED}. + You are receiving this message because our information concerning {EN_NAME} has not been + updated in the last 6 months and your email address is currently listed as the contact + information for this {EN_TYPE}. + If you are no longer the contact for {EN_NAME}, you can use this form + "https://code.open.canada.ca/en/{EN_FORM}.html" to update our platform. + + "https://code.open.canada.ca/en/index.html" + + Message en français: + + Message automatisé concernant {FR_NAME} sur la plateforme Échange de Ressources Ouvert, + mise à jour la plus récente {LAST_UPDATED} + Vous recevez ce message parce que notre information concernant {FR_NAME} n'a pas été + mis a jour dans les 6 derniers mois et votre adresse email est inscrite comme + adresse de contact pour ce {FR_TYPE}. + Si vous n'êtes plus la personne à contacter pour {FR_NAME}, vous pouvez utiliser + ce formulaire "https://code.open.canada.ca/en/{FR_FORM}.html" pour mettre + a jour notre plateforme. + + "https://code.ouvert.canada.ca/fr/index.html" + """ + +