diff --git a/Pipfile b/Pipfile index d675547..b1f54b3 100644 --- a/Pipfile +++ b/Pipfile @@ -12,7 +12,7 @@ pydantic = "*" pytest = "*" coverage = "*" pytest-cov = "*" -moto = {extras = ["dynamodb"], version = "4.2.13"} +moto = {extras = ["dynamodb"], version = "==4.2.13"} pyjwt = "*" google-api-python-client = "*" google-auth-httplib2 = "*" @@ -21,6 +21,7 @@ thefuzz = "*" sentry-sdk = {extras = ["chalice"], version = "*"} pre-commit = "*" ruff = "*" +mongomock = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index f1fac04..6b86193 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "fe5cef9c766a49c7ccb20629c22c6b62e4137c0b52069ca293844ebe38adae27" + "sha256": "5c44c94f637751c8e3407f2b65a575e38f307c15b76475790684ffc5a91b9192" }, "pipfile-spec": 6, "requires": { @@ -34,20 +34,19 @@ }, "boto3": { "hashes": [ - "sha256:72daee953cfa0631c584c9e3aef594079e1fe6a2f64c81ff791dab9a7b25c013", - "sha256:cae11cb54f79795e44248a9e53ec5c7328519019df1ba54bc01413f51c548626" + "sha256:2f3e88b10b8fcc5f6100a9d74cd28230edc9d4fa226d99dd40a3ab38ac213673", + "sha256:b8433d481d50b68a0162c0379c0dd4aabfc3d1ad901800beb5b87815997511c1" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==1.34.142" + "version": "==1.34.144" }, "botocore": { "hashes": [ - "sha256:2eeb8e6be729c1f8ded723970ed6c6ac29cc3014d86a99e73428fa8bdca81f63", - "sha256:9d8095bab0b93b9064e856730a7ffbbb4f897353d3170bec9ddccc5f4a3753bc" + "sha256:4215db28d25309d59c99507f1f77df9089e5bebbad35f6e19c7c44ec5383a3e8", + "sha256:a2cf26e1bf10d5917a2285e50257bc44e94a1d16574f282f3274f7a5d8d1f08b" ], "markers": "python_version >= '3.8'", - "version": "==1.34.142" + "version": "==1.34.144" }, "cachetools": { "hashes": [ @@ -232,7 +231,7 @@ "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" ], - "markers": "python_full_version >= '3.7.0'", + "markers": "python_version >= '3.7'", "version": "==3.3.2" }, "click": { @@ -245,62 +244,61 @@ }, "coverage": { "hashes": [ - "sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f", - "sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d", - "sha256:042183de01f8b6d531e10c197f7f0315a61e8d805ab29c5f7b51a01d62782747", - "sha256:1014fbf665fef86cdfd6cb5b7371496ce35e4d2a00cda501cf9f5b9e6fced69f", - "sha256:1137f46adb28e3813dec8c01fefadcb8c614f33576f672962e323b5128d9a68d", - "sha256:16852febd96acd953b0d55fc842ce2dac1710f26729b31c80b940b9afcd9896f", - "sha256:2174e7c23e0a454ffe12267a10732c273243b4f2d50d07544a91198f05c48f47", - "sha256:2214ee920787d85db1b6a0bd9da5f8503ccc8fcd5814d90796c2f2493a2f4d2e", - "sha256:3257fdd8e574805f27bb5342b77bc65578e98cbc004a92232106344053f319ba", - "sha256:3684bc2ff328f935981847082ba4fdc950d58906a40eafa93510d1b54c08a66c", - "sha256:3a6612c99081d8d6134005b1354191e103ec9705d7ba2754e848211ac8cacc6b", - "sha256:3d7564cc09dd91b5a6001754a5b3c6ecc4aba6323baf33a12bd751036c998be4", - "sha256:44da56a2589b684813f86d07597fdf8a9c6ce77f58976727329272f5a01f99f7", - "sha256:5013ed890dc917cef2c9f765c4c6a8ae9df983cd60dbb635df8ed9f4ebc9f555", - "sha256:54317c2b806354cbb2dc7ac27e2b93f97096912cc16b18289c5d4e44fc663233", - "sha256:56b4eafa21c6c175b3ede004ca12c653a88b6f922494b023aeb1e836df953ace", - "sha256:581ea96f92bf71a5ec0974001f900db495488434a6928a2ca7f01eee20c23805", - "sha256:5cd64adedf3be66f8ccee418473c2916492d53cbafbfcff851cbec5a8454b136", - "sha256:5df54843b88901fdc2f598ac06737f03d71168fd1175728054c8f5a2739ac3e4", - "sha256:65e528e2e921ba8fd67d9055e6b9f9e34b21ebd6768ae1c1723f4ea6ace1234d", - "sha256:6aae5cce399a0f065da65c7bb1e8abd5c7a3043da9dceb429ebe1b289bc07806", - "sha256:6cfb5a4f556bb51aba274588200a46e4dd6b505fb1a5f8c5ae408222eb416f99", - "sha256:7076b4b3a5f6d2b5d7f1185fde25b1e54eb66e647a1dfef0e2c2bfaf9b4c88c8", - "sha256:73ca8fbc5bc622e54627314c1a6f1dfdd8db69788f3443e752c215f29fa87a0b", - "sha256:79b356f3dd5b26f3ad23b35c75dbdaf1f9e2450b6bcefc6d0825ea0aa3f86ca5", - "sha256:7a892be37ca35eb5019ec85402c3371b0f7cda5ab5056023a7f13da0961e60da", - "sha256:8192794d120167e2a64721d88dbd688584675e86e15d0569599257566dec9bf0", - "sha256:820bc841faa502e727a48311948e0461132a9c8baa42f6b2b84a29ced24cc078", - "sha256:8f894208794b164e6bd4bba61fc98bf6b06be4d390cf2daacfa6eca0a6d2bb4f", - "sha256:a04e990a2a41740b02d6182b498ee9796cf60eefe40cf859b016650147908029", - "sha256:a44963520b069e12789d0faea4e9fdb1e410cdc4aab89d94f7f55cbb7fef0353", - "sha256:a6bb74ed465d5fb204b2ec41d79bcd28afccf817de721e8a807d5141c3426638", - "sha256:ab73b35e8d109bffbda9a3e91c64e29fe26e03e49addf5b43d85fc426dde11f9", - "sha256:aea072a941b033813f5e4814541fc265a5c12ed9720daef11ca516aeacd3bd7f", - "sha256:b1ccf5e728ccf83acd313c89f07c22d70d6c375a9c6f339233dcf792094bcbf7", - "sha256:b385d49609f8e9efc885790a5a0e89f2e3ae042cdf12958b6034cc442de428d3", - "sha256:b3d45ff86efb129c599a3b287ae2e44c1e281ae0f9a9bad0edc202179bcc3a2e", - "sha256:b4a474f799456e0eb46d78ab07303286a84a3140e9700b9e154cfebc8f527016", - "sha256:b95c3a8cb0463ba9f77383d0fa8c9194cf91f64445a63fc26fb2327e1e1eb088", - "sha256:c5986ee7ea0795a4095ac4d113cbb3448601efca7f158ec7f7087a6c705304e4", - "sha256:cdd31315fc20868c194130de9ee6bfd99755cc9565edff98ecc12585b90be882", - "sha256:cef4649ec906ea7ea5e9e796e68b987f83fa9a718514fe147f538cfeda76d7a7", - "sha256:d05c16cf4b4c2fc880cb12ba4c9b526e9e5d5bb1d81313d4d732a5b9fe2b9d53", - "sha256:d2e344d6adc8ef81c5a233d3a57b3c7d5181f40e79e05e1c143da143ccb6377d", - "sha256:d45d3cbd94159c468b9b8c5a556e3f6b81a8d1af2a92b77320e887c3e7a5d080", - "sha256:db14f552ac38f10758ad14dd7b983dbab424e731588d300c7db25b6f89e335b5", - "sha256:dbc5958cb471e5a5af41b0ddaea96a37e74ed289535e8deca404811f6cb0bc3d", - "sha256:ddbd2f9713a79e8e7242d7c51f1929611e991d855f414ca9996c20e44a895f7c", - "sha256:e16f3d6b491c48c5ae726308e6ab1e18ee830b4cdd6913f2d7f77354b33f91c8", - "sha256:e2afe743289273209c992075a5a4913e8d007d569a406ffed0bd080ea02b0633", - "sha256:e564c2cf45d2f44a9da56f4e3a26b2236504a496eb4cb0ca7221cd4cc7a9aca9", - "sha256:ed550e7442f278af76d9d65af48069f1fb84c9f745ae249c1a183c1e9d1b025c" + "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382", + "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1", + "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac", + "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee", + "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166", + "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57", + "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c", + "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b", + "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51", + "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da", + "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450", + "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2", + "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd", + "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d", + "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d", + "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6", + "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca", + "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169", + "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1", + "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713", + "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b", + "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6", + "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c", + "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605", + "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463", + "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b", + "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6", + "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5", + "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63", + "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c", + "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783", + "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44", + "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca", + "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8", + "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d", + "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390", + "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933", + "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67", + "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b", + "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03", + "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b", + "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791", + "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb", + "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807", + "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6", + "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2", + "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428", + "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd", + "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c", + "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94", + "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8", + "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==7.5.4" + "version": "==7.6.0" }, "cryptography": { "hashes": [ @@ -364,11 +362,11 @@ }, "exceptiongroup": { "hashes": [ - "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", - "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" + "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", + "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" ], "markers": "python_version < '3.11'", - "version": "==1.2.1" + "version": "==1.2.2" }, "filelock": { "hashes": [ @@ -392,7 +390,6 @@ "sha256:e739cb74aac8258b1886cb853b0722d47c81fe07ad649d7f2206f06530513c04" ], "index": "pypi", - "markers": "python_version >= '3.7'", "version": "==2.137.0" }, "google-auth": { @@ -417,7 +414,6 @@ "sha256:afd0cad092a2eaa53cd8e8298557d6de1034c6cb4a740500b5357b648af97263" ], "index": "pypi", - "markers": "python_version >= '3.6'", "version": "==1.2.1" }, "googleapis-common-protos": { @@ -550,6 +546,14 @@ "markers": "python_version >= '3.7'", "version": "==2.1.5" }, + "mongomock": { + "hashes": [ + "sha256:08a24938a05c80c69b6b8b19a09888d38d8c6e7328547f94d46cadb7f47209f2", + "sha256:f06cd62afb8ae3ef63ba31349abd220a657ef0dd4f0243a29587c5213f931b7d" + ], + "index": "pypi", + "version": "==4.1.2" + }, "moto": { "extras": [ "dynamodb" @@ -558,7 +562,7 @@ "sha256:01aef6a489a725c8d725bd3dc6f70ff1bedaee3e2641752e4b471ff0ede4b4d7", "sha256:93e0fd13b624bd79115494f833308c3641b2be0fc9f4f18aa9264aa01f6168e0" ], - "markers": "python_version >= '3.7'", + "index": "pypi", "version": "==4.2.13" }, "nodeenv": { @@ -615,7 +619,6 @@ "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5" ], "index": "pypi", - "markers": "python_version >= '3.9'", "version": "==3.7.1" }, "proto-plus": { @@ -680,7 +683,6 @@ "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8" ], "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==2.8.2" }, "pydantic-core": { @@ -784,7 +786,6 @@ "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" ], "index": "pypi", - "markers": "python_version >= '3.7'", "version": "==2.8.0" }, "pymongo": { @@ -843,6 +844,7 @@ "sha256:f5bf0eb8b6ef40fa22479f09375468c33bebb7fe49d14d9c96c8fd50355188b0", "sha256:fdc20cd1e1141b04696ffcdb7c71e8a4a665db31fe72e51ec706b3bdd2d09f36" ], + "index": "pypi", "markers": "python_version >= '3.8'", "version": "==4.8.0" }, @@ -860,7 +862,6 @@ "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" ], "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==8.2.2" }, "pytest-cov": { @@ -869,7 +870,6 @@ "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857" ], "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==5.0.0" }, "python-dateutil": { @@ -886,7 +886,6 @@ "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==1.0.1" }, "python-editor": { @@ -1117,7 +1116,6 @@ "sha256:f0368d765eec8247b8550251c49ebb20554cc4e812f383ff9f5bf0d5d94190b0" ], "index": "pypi", - "markers": "python_version >= '3.7'", "version": "==0.5.1" }, "s3transfer": { @@ -1128,16 +1126,22 @@ "markers": "python_version >= '3.8'", "version": "==0.10.2" }, + "sentinels": { + "hashes": [ + "sha256:7be0704d7fe1925e397e92d18669ace2f619c92b5d4eb21a89f31e026f9ff4b1" + ], + "version": "==1.0.0" + }, "sentry-sdk": { "extras": [ "chalice" ], "hashes": [ - "sha256:6051562d2cfa8087bb8b4b8b79dc44690f8a054762a29c07e22588b1f619bfb5", - "sha256:aa4314f877d9cd9add5a0c9ba18e3f27f99f7de835ce36bd150e48a41c7c646f" + "sha256:0bea5fa8b564cc0d09f2e6f55893e8f70286048b0ffb3a341d5b695d1af0e6ee", + "sha256:4c85bad74df9767976afb3eeddc33e0e153300e887d637775a753a35ef99bee6" ], - "markers": "python_version >= '3.6'", - "version": "==2.8.0" + "index": "pypi", + "version": "==2.9.0" }, "setuptools": { "hashes": [ @@ -1161,7 +1165,6 @@ "sha256:7138039a7ecf540da323792d8592ef9902b1d79eb78c147d4f20664de79f3680" ], "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==0.22.1" }, "tomli": { diff --git a/chalicelib/api/events.py b/chalicelib/api/events.py index 030b5ef..90af958 100644 --- a/chalicelib/api/events.py +++ b/chalicelib/api/events.py @@ -98,6 +98,12 @@ def create_rush_event(): def modify_rush_event(): data = events_api.current_request.json_body return event_service.modify_rush_event(data) + +@events_api.route("/events/rush/settings", methods=["PATCH"], cors=True) +@auth(events_api, roles=["admin"]) +def modify_rush_settings(): + data = events_api.current_request.json_body + return event_service.modify_rush_settings(data) @events_api.route("/events/rush/checkin/{event_id}", methods=["POST"], cors=True) diff --git a/chalicelib/modules/mongo.py b/chalicelib/modules/mongo.py index f5698bd..a3783cb 100644 --- a/chalicelib/modules/mongo.py +++ b/chalicelib/modules/mongo.py @@ -1,5 +1,6 @@ from pymongo.mongo_client import MongoClient from bson import ObjectId +import mongomock import boto3 import os @@ -7,8 +8,13 @@ class MongoModule: """Manages connections to MongoDB.""" - def __init__(self): + def __init__(self, use_mock=False): """Establishes connection to MongoDB server""" + self.use_mock = use_mock + if use_mock: + self.mongo_client = mongomock.MongoClient() + return + self.is_prod = os.environ.get("ENV") == "prod" self.ssm_client = boto3.client("ssm") self.user = self.ssm_client.get_parameter( @@ -205,6 +211,55 @@ def update_document(self, collection, document_id, query, array_filters=None): ) return False + @add_env_suffix + def update_many_documents(self, collection: str, filter_query: dict, update_query: dict, array_filters=None) -> dict: + """ + Updates multiple documents in the specified collection that match the given filter query. + + Args: + collection (str): The name of the collection to update the documents in. + filter_query (dict): A dictionary containing the filter criteria for selecting documents to update. + update_query (dict): A dictionary containing the update operators. + array_filters (list, optional): A list of filters to apply when updating + elements in an array field of the document. + Each filter in the list is a dictionary + specifying the criteria for selecting + array elements to be updated. Default is None. + + Returns: + dict: A dictionary containing the count of matched and modified documents. + """ + try: + update_options = {} + if array_filters: + # ensure array_filters is a list + if not isinstance(array_filters, list): + raise ValueError("array_filters must be a list.") + # ensure each item contains a dictionary + for f in array_filters: + if not isinstance(f, dict): + raise ValueError("Each item in array_filters must be a dictionary.") + update_options["array_filters"] = array_filters + + result = self.mongo_client.vault[collection].update_many( + filter_query, update_query, **update_options + ) + + if result.matched_count > 0: + print(f"{result.matched_count} documents matched the filter query.") + print(f"{result.modified_count} documents were updated.") + return { + "matched_count": result.matched_count, + "modified_count": result.modified_count, + } + else: + print("No documents matched the filter query.") + return {"matched_count": 0, "modified_count": 0} + except Exception as e: + print(f"An error occurred while updating documents: {e}") + return {"matched_count": 0, "modified_count": 0} + + @add_env_suffix def get_document_by_id(self, collection, document_id): """ diff --git a/chalicelib/services/EventService.py b/chalicelib/services/EventService.py index c63eb09..b3701ca 100644 --- a/chalicelib/services/EventService.py +++ b/chalicelib/services/EventService.py @@ -5,6 +5,7 @@ import datetime from chalicelib.modules.google_sheets import GoogleSheetsModule from chalicelib.modules.ses import ses, SesDestination +from typing import Optional class EventService: @@ -331,6 +332,47 @@ def modify_rush_event(self, data: dict): print("error is ", e) raise BadRequestError(e) + def modify_rush_settings(self, data: dict): + """ + Updates defaultRushCategory from the rush collection + + Parameters + ---------- + data: dict + contains default_rush_category_id ID of the rush category to be default + + Raises + ------ + BadRequestError + If default_rush_category_id is not in the rush collection + """ + default_rush_category_id = data["defaultRushCategoryId"] + + collection = f"{self.collection_prefix}rush" + + # Set all defaultRushCategory fields to false + mongo_module.update_many_documents( + collection, + {}, + {"$set": {"defaultRushCategory": False}} + ) + + # if default_rush_category_id is "" --> reset defaultRushCategory + if not default_rush_category_id: + return + + # Update the specified document to set its defaultRushCategory to true + result = mongo_module.update_document_by_id( + collection, + default_rush_category_id, + {"defaultRushCategory": True} + ) + + if not result: + raise ValueError(f"Document with ID {default_rush_category_id} was not found or could not be updated.") + + return + def get_rush_event(self, event_id: str, hide_attendees: bool = True): event = mongo_module.get_document_by_id( f"{self.collection_prefix}rush-event", event_id diff --git a/tests/api/test_applicants.py b/tests/api/test_applicants.py index fec61a3..02b22c8 100644 --- a/tests/api/test_applicants.py +++ b/tests/api/test_applicants.py @@ -1,6 +1,5 @@ -from chalice.app import Request from chalice.test import Client -from unittest.mock import MagicMock, patch +from unittest.mock import patch from app import app diff --git a/tests/api/test_events.py b/tests/api/test_events.py new file mode 100644 index 0000000..c6a1b58 --- /dev/null +++ b/tests/api/test_events.py @@ -0,0 +1,326 @@ +from chalice.test import Client +from unittest.mock import patch +import json + +from app import app + +with open("tests/fixtures/events/general/sample_timeframes.json") as f: + SAMPLE_TIMEFRAMES = json.load(f) + +with open("tests/fixtures/events/general/sample_timeframe_sheets.json") as f: + SAMPLE_TIMEFRAME_SHEETS = json.load(f) + +with open("tests/fixtures/events/general/sample_rush_events.json") as f: + SAMPLE_RUSH_EVENTS = json.load(f) + +with open("tests/fixtures/events/general/sample_rush_event.json") as f: + SAMPLE_RUSH_EVENT = json.load(f) + +def test_create_timeframe(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.create_timeframe" + ) as mock_create_timeframe: + mock_create_timeframe.return_value = {"msg": True} + response = client.http.post( + f"/timeframes", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + + +def test_get_all_timeframes(): + # Create a Chalice test client + with Client(app) as client: + # Mock applicant_service's get method + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.get_all_timeframes", + ) as mock_get_all_timeframes: + mock_get_all_timeframes.return_value = SAMPLE_TIMEFRAMES + response = client.http.get( + f"/timeframes", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + # Check the response status code and body + assert response.status_code == 200 + assert response.json_body == SAMPLE_TIMEFRAMES + +def test_get_timeframe(): + # Create a Chalice test client + with Client(app) as client: + # Mock applicant_service's get method + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.get_timeframe", + ) as mock_get_timeframe: + mock_get_timeframe.return_value = SAMPLE_TIMEFRAMES[0] + response = client.http.get( + f"/timeframes/test_timeframe_id", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + # Check the response status code and body + assert response.status_code == 200 + assert response.json_body == SAMPLE_TIMEFRAMES[0] + +def test_delete_timeframe(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.delete_timeframe", + ) as mock_delete: + mock_delete.return_value = {"status": True} + response = client.http.delete( + f"/timeframes/{SAMPLE_TIMEFRAMES[0]['_id']}", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {'status': True} + + +def test_create_event(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.create_event" + ) as mock_create_event: + mock_create_event.return_value = {"msg": True} + response = client.http.post( + f"/timeframes/{SAMPLE_TIMEFRAMES[0]['_id']}/events", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + +def test_get_event(): + # Create a Chalice test client + with Client(app) as client: + # Mock applicant_service's get method + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.get_timeframe", + ) as mock_get_timeframe: + mock_get_timeframe.return_value = SAMPLE_TIMEFRAMES[0] + response = client.http.get( + f"/timeframes/test_timeframe_id", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + # Check the response status code and body + assert response.status_code == 200 + assert response.json_body == SAMPLE_TIMEFRAMES[0] + +def test_get_timeframe_sheets(): + # Create a Chalice test client + with Client(app) as client: + # Mock applicant_service's get method + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.get_timeframe_sheets", + ) as mock_get_timeframe_sheets: + mock_get_timeframe_sheets.return_value = SAMPLE_TIMEFRAME_SHEETS + response = client.http.get( + f"/timeframes/test_timeframe_id/sheets", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + # Check the response status code and body + assert response.status_code == 200 + assert response.json_body == SAMPLE_TIMEFRAME_SHEETS + +def test_checkin(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.checkin" + ) as mock_checkin: + mock_checkin.return_value = {"msg": True} + response = client.http.post( + f"/events/test_event_id/checkin", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + +def test_delete_event(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.delete", + ) as mock_delete: + mock_delete.return_value = {"status": True} + response = client.http.delete( + f"/events/test_event_id", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {'status': True} + +def test_get_rush_events(): + # Create a Chalice test client + with Client(app) as client: + # Mock applicant_service's get method + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.get_rush_categories_and_events", + ) as mock_get_rush_categories_and_events: + mock_get_rush_categories_and_events.return_value = SAMPLE_RUSH_EVENTS + response = client.http.get( + f"/events/rush", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + # Check the response status code and body + assert response.status_code == 200 + assert response.json_body == SAMPLE_RUSH_EVENTS + +def test_get_rush_event(): + # Create a Chalice test client + with Client(app) as client: + # Mock applicant_service's get method + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.get_rush_event", + ) as mock_get_rush_event: + mock_get_rush_event.return_value = SAMPLE_RUSH_EVENT + response = client.http.get( + f"/events/rush/test_event_id", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + # Check the response status code and body + assert response.status_code == 200 + assert response.json_body == SAMPLE_RUSH_EVENT + +def test_create_rush_category(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.create_rush_category" + ) as mock_create_rush_category: + mock_create_rush_category.return_value = {"msg": True} + response = client.http.post( + f"/events/rush/category", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + +def test_create_rush_event(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.create_rush_event" + ) as mock_create_rush_event: + mock_create_rush_event.return_value = {"msg": True} + response = client.http.post( + f"/events/rush", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + +def test_modify_rush_event(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.modify_rush_event" + ) as mock_modify_rush_event: + mock_modify_rush_event.return_value = {"msg": True} + response = client.http.patch( + f"/events/rush", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + +def test_modify_rush_settings(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.modify_rush_settings" + ) as mock_modify_rush_settings: + mock_modify_rush_settings.return_value = {"msg": True} + response = client.http.patch( + f"/events/rush/settings", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + +def test_checkin_rush(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.checkin_rush" + ) as mock_checkin_rush: + mock_checkin_rush.return_value = {"msg": True} + response = client.http.post( + f"/events/rush/checkin/test_event_id", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {"msg": True} + +def test_delete_rush_event(): + with Client(app) as client: + with patch("chalicelib.decorators.jwt.decode") as mock_decode: + # Assuming the decoded token has the required role + mock_decode.return_value = {"role": "admin"} + with patch( + "chalicelib.services.EventService.event_service.delete_rush_event", + ) as mock_delete_rush_event: + mock_delete_rush_event.return_value = {"status": True} + response = client.http.delete( + f"/events/rush/test_event_id", + headers={"Authorization": "Bearer SAMPLE_TOKEN_STRING"}, + ) + + assert response.status_code == 200 + assert response.json_body == {'status': True} \ No newline at end of file diff --git a/tests/api/test_insights.py b/tests/api/test_insights.py index 8d65dd2..ccec7b3 100644 --- a/tests/api/test_insights.py +++ b/tests/api/test_insights.py @@ -1,6 +1,5 @@ -from chalice.app import Request from chalice.test import Client -from unittest.mock import MagicMock, patch +from unittest.mock import patch import json from app import app diff --git a/tests/api/test_listings.py b/tests/api/test_listings.py index 1c54a34..b3728a6 100644 --- a/tests/api/test_listings.py +++ b/tests/api/test_listings.py @@ -1,6 +1,5 @@ -from chalice.app import Request from chalice.test import Client -from unittest.mock import MagicMock, patch +from unittest.mock import patch from chalice import NotFoundError, BadRequestError diff --git a/tests/fixtures/events/general/sample_rush_event.json b/tests/fixtures/events/general/sample_rush_event.json new file mode 100644 index 0000000..d0486cd --- /dev/null +++ b/tests/fixtures/events/general/sample_rush_event.json @@ -0,0 +1,11 @@ +{ + "_id": "668ac7fd961912025eff6e1c", + "categoryId": "668ab777b97edcf7e0dd7c62", + "name": "Info Session 1", + "location": "EPC 204", + "date": "2024-07-07T16:52:32.071Z", + "deadline": "2024-07-07T18:52:32.071Z", + "dateCreated": "2024-07-07T12:53:17.418000", + "lastModified": "2024-07-07T13:25:39.525000", + "eventId": "668ac7fd961912025eff6e1c" +} \ No newline at end of file diff --git a/tests/fixtures/events/general/sample_rush_events.json b/tests/fixtures/events/general/sample_rush_events.json new file mode 100644 index 0000000..ad84bee --- /dev/null +++ b/tests/fixtures/events/general/sample_rush_events.json @@ -0,0 +1,44 @@ +[ + { + "_id": "6689c9ad461be403487c0bf6", + "name": "Test default", + "defaultRushCategory": false, + "dateCreated": "2024-07-06T18:48:13.498000", + "events": [] + }, + { + "_id": "668ab770b97edcf7e0dd7c61", + "name": "Spring 2024", + "defaultRushCategory": false, + "dateCreated": "2024-07-07T11:42:40.365000", + "events": [] + }, + { + "_id": "668ab777b97edcf7e0dd7c62", + "name": "Fall 2024", + "defaultRushCategory": false, + "dateCreated": "2024-07-07T11:42:47.334000", + "events": [ + { + "_id": "668ac7fd961912025eff6e1c", + "name": "Info Session 1", + "code": "info", + "location": "EPC 204", + "date": "2024-07-07T16:52:32.071Z", + "deadline": "2024-07-07T18:52:32.071Z", + "dateCreated": "2024-07-07T12:53:17.418000", + "lastModified": "2024-07-07T13:25:39.525000", + "attendees": [], + "numAttendees": 0, + "eventId": "668ac7fd961912025eff6e1c" + } + ] + }, + { + "_id": "668eb4d9bb65e34f7746ae71", + "name": "Spring 2025", + "defaultRushCategory": false, + "dateCreated": "2024-07-10T12:20:41.851000", + "events": [] + } +] \ No newline at end of file diff --git a/tests/fixtures/events/general/sample_timeframe_sheets.json b/tests/fixtures/events/general/sample_timeframe_sheets.json new file mode 100644 index 0000000..5fc83c1 --- /dev/null +++ b/tests/fixtures/events/general/sample_timeframe_sheets.json @@ -0,0 +1,13 @@ +[ + "Details", + "Leaderboard", + "Brothers Info", + "Total", + "Rush", + "Copy of Rush", + "Chapter", + "Fundraising", + "Teams", + "Events", + "Pledge Class" +] \ No newline at end of file diff --git a/tests/fixtures/events/general/sample_timeframes.json b/tests/fixtures/events/general/sample_timeframes.json new file mode 100644 index 0000000..c0bb251 --- /dev/null +++ b/tests/fixtures/events/general/sample_timeframes.json @@ -0,0 +1,294 @@ +[ + { + "_id": "66087df56fa3fb414972106b", + "name": "Fall 2023 - Test", + "dateCreated": "2024-03-30T17:02:45.353000", + "events": [ + { + "name": "Rush - Professional Panel", + "dateCreated": "2024-03-30T17:03:01.534000", + "timeframeId": "66087df56fa3fb414972106b", + "usersAttended": [], + "_id": "66087e056fa3fb414972106c", + "eventId": "None" + } + ], + "spreadsheetId": "1qSr4nrWxh3JEyz1A5chy2BictSP5xeUYxfzpZo8s3OE" + }, + { + "_id": "660895a36fa3fb414972106e", + "name": "Spring 2024", + "dateCreated": "2024-03-30T18:43:47.164000", + "events": [ + { + "name": "Chapter #2", + "tags": [ + "Chapter" + ], + "dateCreated": "2024-03-30T20:07:27.037000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6608a93f93bd0645cfbea76f", + "eventId": "None" + }, + { + "name": "Rush - Professional Panel", + "tags": [ + "Rush", + "Recruitment" + ], + "dateCreated": "2024-03-30T20:07:52.514000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6608a95893bd0645cfbea770", + "eventId": "None" + }, + { + "name": "Mobile Test", + "tags": [ + "Test" + ], + "dateCreated": "2024-03-31T15:11:36.361000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "66097d28b1676ff30e2013e9", + "eventId": "None" + }, + { + "name": "test", + "tags": [ + "1", + "2", + "3" + ], + "dateCreated": "2024-03-31T17:11:32.451000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6609994479bb0f98429a203e", + "eventId": "None" + }, + { + "name": "test", + "tags": [ + "123" + ], + "dateCreated": "2024-04-08T14:51:40.524000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "66143cbc03dc0e897a754217", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:07:24.171000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "661567bc649f7b9cc800cc8f", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:07:47.388000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "661567d33d373f47bab97d9f", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:09:08.373000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "661568248e117e2ec75a9b14", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:09:44.825000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "661568489788689e69c4f450", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:10:03.146000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6615685b9788689e69c4f451", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:11:59.416000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "661568cfb4554b8732fabaa4", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:13:19.444000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6615691f83737f75748b346f", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "dateCreated": "2024-04-09T12:13:37", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6615693183737f75748b3470", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:14:08.703000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6615695083737f75748b3471", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:14:31.891000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6615696706e364d836e334ad", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:15:01.169000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "6615698594eff08c048f1743", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:16:52.605000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "661569f4d4ff3f38b7222248", + "eventId": "None" + }, + { + "name": "123123123", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:17:12.387000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "66156a08efec1d2f8ea4b415", + "eventId": "None" + }, + { + "name": "check-in test", + "tags": [ + "123" + ], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:17:43.676000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "_id": "66156a27efec1d2f8ea4b416", + "eventId": "None" + }, + { + "name": "spreadsheet col please work", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:47:18.083000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "spreadsheetCol": "J", + "_id": "66157117a8f38c63b8955e4d", + "eventId": "None" + }, + { + "name": "final test", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-09T12:49:03.991000", + "timeframeId": "660895a36fa3fb414972106e", + "usersAttended": [], + "spreadsheetCol": "K", + "_id": "66157181f8c8d95dc97b09e5", + "eventId": "None" + } + ], + "spreadsheetId": "1_LJEwFVKVzFd3kiaftlpi6-zPcsPfg9IivdaHpBpk2I" + }, + { + "_id": "6615f3912a689bd2d93d8e1f", + "name": "Fall 2024", + "spreadsheetId": "1_LJEwFVKVzFd3kiaftlpi6-zPcsPfg9IivdaHpBpk2I", + "dateCreated": "2024-04-09T22:04:01.392000", + "events": [ + { + "name": "Chapter - April 17", + "tags": [ + "Chapter" + ], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-17T19:16:15.672000", + "timeframeId": "6615f3912a689bd2d93d8e1f", + "usersAttended": [], + "spreadsheetCol": "H", + "_id": "66205840febfc8688db7c7e6", + "eventId": "66205840febfc8688db7c7e6" + }, + { + "name": "test", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-24T15:19:15.742000", + "timeframeId": "6615f3912a689bd2d93d8e1f", + "usersAttended": [], + "spreadsheetCol": "J", + "_id": "66295b344895f2954f3f8afa", + "eventId": "66295b344895f2954f3f8afa" + }, + { + "name": "Chapter (04/24)", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-24T15:20:38.238000", + "timeframeId": "6615f3912a689bd2d93d8e1f", + "usersAttended": [], + "spreadsheetCol": "K", + "_id": "66295b87b49ca09a9e23792a", + "eventId": "66295b87b49ca09a9e23792a" + }, + { + "name": "Final Chapter (April 24)", + "tags": [], + "sheetTab": "Copy of Rush", + "dateCreated": "2024-04-24T15:26:02.591000", + "timeframeId": "6615f3912a689bd2d93d8e1f", + "usersAttended": [], + "spreadsheetCol": "M", + "_id": "66295ccb0d5296ea797fb449", + "eventId": "66295ccb0d5296ea797fb449" + } + ] + } +] \ No newline at end of file