diff --git a/.gitignore b/.gitignore index 37f7661e841453a5a126f7eb7a3f2fb9a5126eb7..5460414a9f83230b5b5958c3f5554420b8c1c46a 100644 --- a/.gitignore +++ b/.gitignore @@ -166,3 +166,4 @@ index.js node_modules package.json package-lock.json +outputlogs.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b25957efa687e13c03c19c1864f909e87101fc8b..89bd77639b9897efea28cee540815c2581a03231 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,3 +18,7 @@ run_script: - pdm sync script: - pdm run vote_reminders + artifacts: + paths: + - outputlogs.json + expire_in: 1 week \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 17724e4ac485f4e88104320f7c9db40cb45749c5..149ffba6a3952dc3f5ded1adec26f7845281d1cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] - -### Fixed - -- Consider timezone +## [1.1.0] - 2025-05-14 +### Added +- Add output logs file +- Add timezone parameter ## [1.0.0] - 2024-06-04 @@ -27,3 +26,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Handle multiple datetime formats - Increase number of survey participants from 10k to 100k + diff --git a/README.md b/README.md index 2fa45b12adbdfab754d92a34742f3e467b9b5f10..d4ae31e1a9746c60d05681e238639de10258e7d8 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,23 @@ Following parameters can only be passed to GitLab-CI: - `FREQ` : CI frequency +### Setting the Timezone + +The default timezone is set to UTC+2. It will be used to compare correctly against the survey expiration date. + +The `--timezone` parameter can be used to set a different timezone. +The parameter is a number of hours to add to UTC to get the local timezone. + +For example, `--timezone 2` for Paris time, `--timezone -4` for New York time. + +### Output file + +The output file is a JSON file that contains all the execution logs. + +The file is saved as `outputlogs.json` and can be found in the root directory of the project when running the script localy and in the GitLab CI artifacts when running in GitLab. + + + ## Documentation - https://manual.limesurvey.org/RemoteControl_2_API diff --git a/pdm.lock b/pdm.lock index c07142b59c06e25041b7ce40de9a6faf337bef26..7299c6df6d069500a548123c812bdb990e6cc483 100644 --- a/pdm.lock +++ b/pdm.lock @@ -46,16 +46,16 @@ files = [ [[package]] name = "citric" -version = "1.0.0" +version = "1.4.0" requires_python = ">=3.8" summary = "A client to the LimeSurvey Remote Control API 2, written in modern Python." groups = ["default"] dependencies = [ - "requests>=2.23", + "requests>=2.25.1", ] files = [ - {file = "citric-1.0.0-py3-none-any.whl", hash = "sha256:89929562f81a574287e5d59564f0c564c77670da8b569eef5f5897eb9c6830aa"}, - {file = "citric-1.0.0.tar.gz", hash = "sha256:a874928ee6416eadfe6ccca28b6eb38dc6fd938db4066f1ba5f272b9c7c7642d"}, + {file = "citric-1.4.0-py3-none-any.whl", hash = "sha256:509bb9cf9800855dbc3ee01c5b0ce5d05c7c4e57bc7414cb685d4de3ff6ae37d"}, + {file = "citric-1.4.0.tar.gz", hash = "sha256:34f3353768770ad7de8202f5efcca3eb1297af9915d9842f7d03d8e8497d58a4"}, ] [[package]] @@ -71,23 +71,23 @@ files = [ [[package]] name = "python-dotenv" -version = "1.0.1" -requires_python = ">=3.8" +version = "1.1.0" +requires_python = ">=3.9" summary = "Read key-value pairs from a .env file and set them as environment variables" groups = ["default"] files = [ - {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, - {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, + {file = "python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d"}, + {file = "python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5"}, ] [[package]] name = "pytz" -version = "2024.1" +version = "2025.2" summary = "World timezone definitions, modern and historical" groups = ["default"] files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, + {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, + {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 5b5b64f5fea2b50fe5863028cdd7f9e2d6a18def..da82056092756dd49ee7c704fe6e51d6ad794f61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "vote_reminders" -version = "0.1.0" -description = "Default template for PDM package" +version = "1.1.0" +description = "Outil de rappel pour les sondages LimeSurvey" authors = [ {name = "Plumtree3D", email = "celeste@lydra.fr"}, ] diff --git a/script.py b/script.py index 25eeccc1a7c0a70ea080bc3f15be0e19e4e649e2..83ae32145cd2e1bb3358114e34f017283b7f4558 100644 --- a/script.py +++ b/script.py @@ -11,6 +11,7 @@ parser.add_argument('-i', '--interval', metavar='N', type=int, help='Intervale m parser.add_argument('-r', '--reminders', metavar='N', type=int, help='Nombre de relances avant d’arrêter de relancer') parser.add_argument('-d', '--delay', metavar='N', type=int, help='Délai au-delà duquel on considère un vote comme abandonné') parser.add_argument('-e', '--expiry', type=datetime.datetime.fromisoformat, help='Date à partir de laquelle les relances du sondage sont terminées, format AAAA-mm-jj:HH:MM') +parser.add_argument('-tz', '--timezone', metavar='N', type=int, help='Fuseau horaire. Entrer seulement le décalage en heures par rapport au fuseau UTC. Exemple: 2 pour l\'Europe/Paris, -4 pour New_York. Par défaut, le fuseau est UTC+2.') args = parser.parse_args() # Initialisation des variables @@ -24,7 +25,7 @@ REMINDER_INTERVAL = args.interval or os.getenv('REMINDER_INTERVAL') REMINDERS = args.reminders or os.getenv('REMINDERS') OVER_DELAY = args.delay or os.getenv('OVER_DELAY') SURVEY_EXPIRATION_DATE = args.expiry or datetime.datetime.fromisoformat(os.getenv('SURVEY_EXPIRATION_DATE')) -NOW = datetime.datetime.now() + datetime.timedelta(hours=int(2)) +NOW = datetime.datetime.now() + datetime.timedelta(hours=int(args.timezone or 0 if args.timezone == 0 else 2)) # Initialisation du client remote control client = Client(f'{URL_API}/index.php/admin/remotecontrol', LOGIN, PASS) @@ -68,19 +69,20 @@ if SURVEY_EXPIRATION_DATE > NOW: participants = client.list_participants(FORM_ID, limit=100000, attributes=["remindersent","remindercount"]) filtered_participants = list(filter(participant_overdue, participants)) - for participant in filtered_participants: - reminder_count = participant['remindercount'] - participant_id=int(participant['tid']) - if int(participant['remindercount']) < int(REMINDERS) : - if participant['remindersent'] == "N" or participant['remindersent'] == None or participant['remindersent'] == '': - print(f"{participant['participant_info']['email']} ({participant_id}), aucun rappel, {reminder_count}/{REMINDERS}") - mail_participant(participant_id) - else: - reminder = get_date(participant['remindersent']) - now = datetime.datetime.today().replace(microsecond=0) + datetime.timedelta(hours=int(2)) - last_reminder = now - reminder - if reminder + datetime.timedelta(hours=int(REMINDER_INTERVAL)) < now: - print(f"{participant['participant_info']['email']} ({participant_id}), dernier rappel il y a {last_reminder}, {reminder_count}/{REMINDERS}") + with open('outputlogs.json', 'w') as f: + for participant in filtered_participants: + reminder_count = participant['remindercount'] + participant_id=int(participant['tid']) + if int(participant['remindercount']) < int(REMINDERS) : + if participant['remindersent'] == "N" or participant['remindersent'] == None or participant['remindersent'] == '': + print(f"{participant['participant_info']['email']} ({participant_id}), aucun rappel, {reminder_count}/{REMINDERS}", file=f) mail_participant(participant_id) + else: + reminder = get_date(participant['remindersent']) + now = datetime.datetime.today().replace(microsecond=0) + datetime.timedelta(hours=int(2)) + last_reminder = now - reminder + if reminder + datetime.timedelta(hours=int(REMINDER_INTERVAL)) < now: + print(f"{participant['participant_info']['email']} ({participant_id}), dernier rappel il y a {last_reminder}, {reminder_count}/{REMINDERS}", file=f) + mail_participant(participant_id) else: print('Sondage terminé')