Add objectives to snapshots

This commit is contained in:
Ramon Wenger 2021-05-11 23:54:08 +02:00
parent 24c88e84ff
commit de26a9f8ac
9 changed files with 219 additions and 85 deletions

83
Pipfile.lock generated
View File

@ -55,19 +55,18 @@
},
"boto3": {
"hashes": [
"sha256:56f1766f1271b6b4e979c7b56225377f8912050e5935adc5c1c9e3a0338b949e",
"sha256:c61c809d288e88b9a0d926f56f803d0128b498aa9b45a42a6e03cd9a83e5c124"
"sha256:2f0d76660d484ff4c8c2efe9171c1281b38681e6806f87cf100e822432eda11e",
"sha256:cbaa8df5faf81730f117bfa0e3fcda68ec3fa9449a05847aa6140a3f4c087765"
],
"index": "pypi",
"version": "==1.17.68"
"version": "==1.17.69"
},
"botocore": {
"hashes": [
"sha256:0f693f5ad6348ec1a62b3a66fee2840d3b722d66b44896022d644275ff8b143d",
"sha256:eb3544911cb0316a33b328a27d137130af278a9c0006be0c95e5e402b01d9865"
"sha256:7e94d3777763ece33d282b437e3b05b5567b9af816bd7819dbe4eb9bc6db6082",
"sha256:f755b19ddebda0f8ab7afc75ebcb5412dd802eca0a7e670f5fff8c5e58bc88b1"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.20.68"
"version": "==1.20.69"
},
"certifi": {
"hashes": [
@ -81,7 +80,6 @@
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"decorator": {
@ -89,7 +87,6 @@
"sha256:6f201a6c4dac3d187352661f508b9364ec8091217442c9478f1f83c003a0f060",
"sha256:945d84890bb20cc4a2f4a31fc4311c0c473af65ea318617f13a7257c9a58bc98"
],
"markers": "python_version >= '3.5'",
"version": "==5.0.7"
},
"dj-database-url": {
@ -189,7 +186,6 @@
"sha256:710b4d15ec1996550cc68a0abbc41903ca7d832540e52b1336e6858737e410d8",
"sha256:bb8f27684814cd1414b2af75b857b5e26a40912631904038a7ecacd2bfafc3ac"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.24.0"
},
"django-treebeard": {
@ -197,7 +193,6 @@
"sha256:7c2b1cdb1e9b46d595825186064a1228bc4d00dbbc186db5b0b9412357fba91c",
"sha256:80150017725239702054e5fa64dc66e383dc13ac262c8d47ee5a82cb005969da"
],
"markers": "python_version >= '3.6'",
"version": "==4.5.1"
},
"djangorestframework": {
@ -228,14 +223,12 @@
"sha256:156854f36d4086bb21ff85a79b4d6a6403a240cd2c17a33a44b8ea4ff4e957c2",
"sha256:a2ed065342e91a7672407325848cd5728d5e5eb4928d0a1c478fd4f0dd97d1f7"
],
"markers": "python_version >= '3.6'",
"version": "==8.1.2"
},
"future": {
"hashes": [
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.18.2"
},
"gprof2dot": {
@ -286,7 +279,6 @@
"sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d",
"sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.1"
},
"idna": {
@ -294,7 +286,6 @@
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
},
"ipython": {
@ -325,7 +316,6 @@
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.11.3"
},
"jmespath": {
@ -333,7 +323,6 @@
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.0"
},
"libsass": {
@ -409,7 +398,6 @@
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.1"
},
"matplotlib-inline": {
@ -417,7 +405,6 @@
"sha256:5cf1176f554abb4fa98cb362aa2b55c500147e4bdbb07e3fda359143e1da0811",
"sha256:f41d5ff73c9f5385775d5c0bc13b424535c8402fe70ea8210f93e11f3683993e"
],
"markers": "python_version >= '3.5'",
"version": "==0.1.2"
},
"newrelic": {
@ -442,7 +429,6 @@
"sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
"sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.9"
},
"parso": {
@ -450,7 +436,6 @@
"sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea",
"sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.7.1"
},
"pexpect": {
@ -526,7 +511,6 @@
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
],
"markers": "python_full_version >= '3.6.1'",
"version": "==3.0.18"
},
"psycopg2": {
@ -562,7 +546,6 @@
"sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068",
"sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.7.0"
},
"pygments": {
@ -570,7 +553,6 @@
"sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f",
"sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"
],
"markers": "python_version >= '3.5'",
"version": "==2.9.0"
},
"pyparsing": {
@ -578,7 +560,6 @@
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"python-dateutil": {
@ -586,7 +567,6 @@
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.1"
},
"python-dotenv": {
@ -672,7 +652,6 @@
"sha256:273bdc0abec649bf6319df7b6267980f79e53ab64e92906d65eea6d4330d00b4",
"sha256:74b0dcf9a79188948f61f456bd1bf67ffa676a5d388aba1c76bff516566d7084"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==6.7.0"
},
"sentry-sdk": {
@ -688,7 +667,6 @@
"sha256:58b46ce1cc4d43af0aac3ac9a047bdb0f44e05f0b2fa2eec755863331700c865",
"sha256:85c97f94c8957fa4e6dab113156c182fb346d56d059af78aad710bced15f16fb"
],
"markers": "python_version >= '2.6'",
"version": "==3.6.1"
},
"six": {
@ -696,7 +674,6 @@
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"sqlparse": {
@ -704,7 +681,6 @@
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
],
"markers": "python_version >= '3.5'",
"version": "==0.4.1"
},
"starkbank-ecdsa": {
@ -725,7 +701,6 @@
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"traitlets": {
@ -733,16 +708,15 @@
"sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396",
"sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"
],
"markers": "python_version >= '3.7'",
"version": "==5.0.5"
},
"typing": {
"hashes": [
"sha256:1187fb9c82fd670d10aa07bbb6cfcfe4bdda42d6fab8d5134f04e8c4d0b71cc9",
"sha256:283d868f5071ab9ad873e5e52268d611e851c870a2ba354193026f2dfb29d8b5"
"sha256:12fbdfbe7d6cca1a42e485229afcb0b0c8259258cfb919b8a5e2a5c953742f89",
"sha256:13b4ad211f54ddbf93e5901a9967b1e07720c1d1b78d596ac6a439641aa1b130",
"sha256:c7219ef20c5fbf413b4567092adfc46fa6203cb8454eda33c3fc1afe1398a308"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==3.7.4.3"
"version": "==3.10.0.0"
},
"unidecode": {
"hashes": [
@ -764,7 +738,6 @@
"sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",
"sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.4"
},
"wagtail": {
@ -826,7 +799,6 @@
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
],
"markers": "python_version >= '3.6'",
"version": "==3.3.4"
},
"autopep8": {
@ -838,11 +810,11 @@
},
"awscli": {
"hashes": [
"sha256:57ae60a3f59cac265a9e5321c618b8768fdee89565089ada271e24489be5110d",
"sha256:a26b5e24f70cb2c542128ccc11e9d38e43cded687d60cd2ca18b3d28cd902509"
"sha256:1098eaf29a066965c0111469df450174f321698e425c0a112d315d091b5461f1",
"sha256:8103f89ba9ca5ccc3b45da97c5c0bd767fcbaff83d720386e57eaa379ff09458"
],
"index": "pypi",
"version": "==1.19.68"
"version": "==1.19.69"
},
"backcall": {
"hashes": [
@ -853,11 +825,10 @@
},
"botocore": {
"hashes": [
"sha256:0f693f5ad6348ec1a62b3a66fee2840d3b722d66b44896022d644275ff8b143d",
"sha256:eb3544911cb0316a33b328a27d137130af278a9c0006be0c95e5e402b01d9865"
"sha256:7e94d3777763ece33d282b437e3b05b5567b9af816bd7819dbe4eb9bc6db6082",
"sha256:f755b19ddebda0f8ab7afc75ebcb5412dd802eca0a7e670f5fff8c5e58bc88b1"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.20.68"
"version": "==1.20.69"
},
"certifi": {
"hashes": [
@ -871,7 +842,6 @@
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"colorama": {
@ -879,7 +849,6 @@
"sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
"sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==0.4.3"
},
"coverage": {
@ -945,7 +914,6 @@
"sha256:6f201a6c4dac3d187352661f508b9364ec8091217442c9478f1f83c003a0f060",
"sha256:945d84890bb20cc4a2f4a31fc4311c0c473af65ea318617f13a7257c9a58bc98"
],
"markers": "python_version >= '3.5'",
"version": "==5.0.7"
},
"django": {
@ -969,7 +937,6 @@
"sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827",
"sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.15.2"
},
"gprof2dot": {
@ -983,7 +950,6 @@
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
},
"ipdb": {
@ -1021,7 +987,6 @@
"sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419",
"sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.11.3"
},
"jmespath": {
@ -1029,7 +994,6 @@
"sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9",
"sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.0"
},
"markupsafe": {
@ -1087,7 +1051,6 @@
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be",
"sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.1.1"
},
"matplotlib-inline": {
@ -1095,7 +1058,6 @@
"sha256:5cf1176f554abb4fa98cb362aa2b55c500147e4bdbb07e3fda359143e1da0811",
"sha256:f41d5ff73c9f5385775d5c0bc13b424535c8402fe70ea8210f93e11f3683993e"
],
"markers": "python_version >= '3.5'",
"version": "==0.1.2"
},
"parso": {
@ -1103,7 +1065,6 @@
"sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea",
"sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.7.1"
},
"pexpect": {
@ -1126,7 +1087,6 @@
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
],
"markers": "python_full_version >= '3.6.1'",
"version": "==3.0.18"
},
"ptyprocess": {
@ -1159,7 +1119,6 @@
"sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068",
"sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.7.0"
},
"pygments": {
@ -1167,7 +1126,6 @@
"sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f",
"sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"
],
"markers": "python_version >= '3.5'",
"version": "==2.9.0"
},
"python-dateutil": {
@ -1175,7 +1133,6 @@
"sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
"sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.1"
},
"pytz": {
@ -1217,7 +1174,6 @@
"sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
"sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==5.4.1"
},
"requests": {
@ -1233,7 +1189,7 @@
"sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2",
"sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"
],
"markers": "python_version >= '3.5' and python_version < '4'",
"markers": "python_version > '2.7'",
"version": "==4.7.2"
},
"s3transfer": {
@ -1248,7 +1204,6 @@
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"sqlparse": {
@ -1256,7 +1211,6 @@
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
],
"markers": "python_version >= '3.5'",
"version": "==0.4.1"
},
"toml": {
@ -1264,7 +1218,6 @@
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"traitlets": {
@ -1272,7 +1225,6 @@
"sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396",
"sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"
],
"markers": "python_version >= '3.7'",
"version": "==5.0.5"
},
"urllib3": {
@ -1280,7 +1232,6 @@
"sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",
"sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.4"
},
"wcwidth": {

View File

@ -0,0 +1,34 @@
# Generated by Django 2.2.22 on 2021-05-11 13:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('objectives', '0014_delete_objectiveprogressstatus'),
('books', '0028_snapshot_shared'),
]
operations = [
migrations.AddField(
model_name='snapshot',
name='hidden_objectives',
field=models.ManyToManyField(related_name='hidden_for_snapshots', to='objectives.Objective'),
),
migrations.CreateModel(
name='ObjectiveGroupSnapshot',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('hidden', models.BooleanField(default=False)),
('objective_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='objectives.ObjectiveGroup')),
('snapshot', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='objective_group_snapshots', to='books.Snapshot')),
],
),
migrations.AddField(
model_name='snapshot',
name='objective_groups',
field=models.ManyToManyField(through='books.ObjectiveGroupSnapshot', to='objectives.ObjectiveGroup'),
),
]

View File

@ -3,6 +3,7 @@ from django.db import models
from django.db.models import Q
from books.models import Chapter, ContentBlock, ContentBlockSnapshot
from objectives.models import ObjectiveSnapshot
class ChapterSnapshot(models.Model):
@ -24,6 +25,19 @@ class ChapterSnapshot(models.Model):
description_hidden = models.BooleanField(default=False)
class ObjectiveGroupSnapshot(models.Model):
objective_group = models.ForeignKey(
'objectives.ObjectiveGroup',
on_delete=models.CASCADE
)
snapshot = models.ForeignKey(
'books.Snapshot',
related_name='objective_group_snapshots',
on_delete=models.CASCADE
)
hidden = models.BooleanField(default=False)
class SnapshotManager(models.Manager):
def create_snapshot(self, module, school_class, user, *args, **kwargs):
snapshot = self.create(module=module, creator=user, *args, **kwargs)
@ -41,7 +55,7 @@ class SnapshotManager(models.Manager):
snapshot.hidden_content_blocks.add(content_block)
for content_block in base_qs.filter(Q(user_created=True) & Q(owner=user)):
new_content_block = ContentBlockSnapshot(
hidden=False,
hidden=False, # todo
snapshot=snapshot,
contents=content_block.contents,
type=content_block.type,
@ -52,6 +66,26 @@ class SnapshotManager(models.Manager):
revision.publish()
new_content_block.save()
for objective_group in module.objective_groups.all():
ObjectiveGroupSnapshot.objects.create(
objective_group=objective_group,
snapshot=snapshot,
hidden=objective_group.hidden_for.filter(id=school_class.id).exists(),
)
base_qs = objective_group.objectives.filter(objectivesnapshot__isnull=True)
for objective in base_qs.filter(owner__isnull=True):
if objective.hidden_for.filter(id=school_class.id).exists():
snapshot.hidden_objectives.add(objective)
for objective in base_qs.filter(owner=user):
ObjectiveSnapshot.objects.create(
hidden=False, # todo
snapshot=snapshot,
text=objective.text,
group=objective_group,
order=objective.order
)
return snapshot
@ -72,6 +106,14 @@ class Snapshot(models.Model):
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True)
shared = models.BooleanField(default=False)
objective_groups = models.ManyToManyField(
'objectives.ObjectiveGroup',
through=ObjectiveGroupSnapshot
)
hidden_objectives = models.ManyToManyField(
'objectives.Objective',
related_name='hidden_for_snapshots'
)
objects = SnapshotManager()

View File

@ -61,13 +61,20 @@ class ApplySnapshot(relay.ClientIDMutation):
for content_block in snapshot.hidden_content_blocks.all():
content_block.hidden_for.add(selected_class)
for custom_content_block in snapshot.custom_content_blocks.all():
custom_content_block.to_regular_content_block(user, selected_class)
custom_content_block.to_regular_content_block(owner=user, school_class=selected_class)
for chapter_snapshot in snapshot.chapters.through.objects.all():
chapter = chapter_snapshot.chapter
if chapter_snapshot.title_hidden:
chapter.title_hidden_for.add(selected_class)
if chapter_snapshot.description_hidden:
chapter.description_hidden_for.add(selected_class)
for objective_group_snapshot in snapshot.objective_groups.through.objects.all():
if objective_group_snapshot.hidden:
objective_group_snapshot.objective_group.hidden_for.add(selected_class)
for objective in snapshot.hidden_objectives.all():
objective.hidden_for.add(selected_class)
for custom_objective in snapshot.custom_objectives.all():
custom_objective.to_regular_objective(owner=user, school_class=selected_class)
return cls(success=True, module=snapshot.module)

View File

@ -2,12 +2,11 @@ import graphene
from django.db.models import Q
from graphene import relay, ObjectType
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField
from books.models.snapshot import Snapshot
from ..interfaces import ModuleInterface, ChapterInterface
from ..interfaces import ChapterInterface
from ..interfaces.contentblock import ContentBlockInterface
from ...models import Module, Chapter, ChapterSnapshot, ContentBlock
from ...models import ContentBlock
class SnapshotContentBlock:
@ -43,6 +42,27 @@ class SnapshotChapter:
# all with snapshotcontentblock with this snapshot
class SnapshotObjective:
def __init__(self, objective, snapshot):
self.text = objective.text
self.hidden = snapshot.hidden_objectives.filter(id=objective.id).exists()
class SnapshotObjectiveGroup:
def __init__(self, objective_group, snapshot):
self.title = objective_group.title
base_qs = objective_group.objectives
default = Q(owner__isnull=True)
this_snapshot = Q(objectivesnapshot__snapshot=snapshot)
self.objectives = [
SnapshotObjective(
objective=objective,
snapshot=snapshot
)
for objective in base_qs.filter(default | this_snapshot)
]
class SnapshotContentBlockNode(ObjectType):
class Meta:
interfaces = (relay.Node, ContentBlockInterface,)
@ -66,6 +86,22 @@ class SnapshotChangesNode(ObjectType):
new_content_blocks = graphene.Int(required=True)
class SnapshotObjectiveNode(ObjectType):
class Meta:
interfaces = (relay.Node,)
hidden = graphene.Boolean(required=True)
text = graphene.String(required=True)
class SnapshotObjectiveGroupNode(ObjectType):
class Meta:
interfaces = (relay.Node,)
title = graphene.String(required=True)
objectives = graphene.List(SnapshotObjectiveNode)
class SnapshotNode(DjangoObjectType):
title = graphene.String()
chapters = graphene.List(SnapshotChapterNode)
@ -75,6 +111,7 @@ class SnapshotNode(DjangoObjectType):
mine = graphene.Boolean()
shared = graphene.Boolean(required=True)
creator = graphene.String(required=True)
objective_groups = graphene.List(SnapshotObjectiveGroupNode)
class Meta:
model = Snapshot
@ -122,3 +159,13 @@ class SnapshotNode(DjangoObjectType):
@staticmethod
def resolve_creator(parent, info, **kwargs):
return f'{parent.creator.first_name} {parent.creator.last_name}'
@staticmethod
def resolve_objective_groups(parent, info, **kwargs):
return [
SnapshotObjectiveGroup(
objective_group=objective_group,
snapshot=parent
)
for objective_group in parent.objective_groups.all()
]

View File

@ -50,12 +50,11 @@ mutation CreateSnapshot($input: CreateSnapshotInput!) {
snapshot {
id
created
creator {
username
}
creator
objectiveGroups {
objectives {
text
hidden
}
}
chapters {
@ -121,9 +120,7 @@ query SnapshotQuery($slug: String!) {
id
title
created
creator {
username
}
creator
}
}
}
@ -206,6 +203,8 @@ class CreateSnapshotTestCase(SkillboxTestCase):
objectives = module['objectiveGroups'][0]['objectives']
self.assertEqual(len(objectives), 3)
hidden_objective = [objective for objective in objectives if
objective['text'] == self.hidden_objective.text][0]
custom_objective = [objective for objective in objectives if
@ -236,7 +235,7 @@ class CreateSnapshotTestCase(SkillboxTestCase):
chapter = snapshot.get('chapters')[0]
self.assertIsNotNone(snapshot.get('created'))
self.assertEqual(snapshot.get('creator').get('username'), self.teacher.username)
self.assertEqual(snapshot.get('creator'), f'{self.teacher.first_name} {self.teacher.last_name}')
self.assertTrue(chapter['titleHidden'])
self.assertFalse(chapter['descriptionHidden'])
@ -267,6 +266,7 @@ class CreateSnapshotTestCase(SkillboxTestCase):
self.snapshot = Snapshot.objects.create_snapshot(module=self.module, school_class=self.skillbox_class,
user=self.teacher)
self.assertEqual(Snapshot.objects.count(), 1)
self.assertEqual(self.snapshot.custom_objectives.count(), 1)
school_class_name = 'second_class'
second_class = SchoolClass.objects.get(name=school_class_name)
request = RequestFactory().get('/')
@ -302,9 +302,6 @@ class CreateSnapshotTestCase(SkillboxTestCase):
self.assertEqual(second['hidden'], True)
self.assertEqual(third['title'], 'custom')
def test_not_too_much_user_creator_info(self):
self.assertTrue(False)
def test_apply_initial_snapshot(self):
teacher2 = User.objects.get(username='teacher2')
teacher2_client = self.get_client(user=teacher2)
@ -364,7 +361,7 @@ class SnapshotTestCase(SkillboxTestCase):
self.assertIsNone(result.get('errors'))
snapshots = result['data']['module']['snapshots']
self.assertEqual(len(snapshots), 1)
self.assertEqual(snapshots[0]['creator']['username'], 'teacher')
self.assertEqual(snapshots[0]['creator'], f'{self.teacher.first_name} {self.teacher.last_name}')
def test_share_snapshot(self):
self.assertFalse(self.snapshot.shared)

View File

@ -0,0 +1,28 @@
# Generated by Django 2.2.22 on 2021-05-11 21:50
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('books', '0029_auto_20210511_1301'),
('objectives', '0014_delete_objectiveprogressstatus'),
]
operations = [
migrations.AlterModelOptions(
name='objective',
options={'verbose_name': 'Lernziel', 'verbose_name_plural': 'Lernziele'},
),
migrations.CreateModel(
name='ObjectiveSnapshot',
fields=[
('objective_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='objectives.Objective')),
('hidden', models.BooleanField(default=False)),
('snapshot', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='custom_objectives', to='books.Snapshot')),
],
bases=('objectives.objective',),
),
]

View File

@ -48,7 +48,8 @@ class Objective(models.Model):
class Meta:
verbose_name = 'Lernziel'
verbose_name_plural = 'Lernziele'
ordering = [F('owner').asc(nulls_first=True), F('order').asc(nulls_last=True)]
# todo: reinstate ordering in resolver
# ordering = [F('owner').asc(nulls_first=True), F('order').asc(nulls_last=True)]
text = models.CharField('text', blank=True, null=False, max_length=255)
group = models.ForeignKey(ObjectiveGroup, blank=False, null=False, on_delete=models.CASCADE,
@ -64,3 +65,26 @@ class Objective(models.Model):
def sync_visibility(self, school_class_template, school_class_to_sync):
sync_hidden_for(self, school_class_template, school_class_to_sync)
sync_visible_for(self, school_class_template, school_class_to_sync)
class ObjectiveSnapshot(Objective):
hidden = models.BooleanField(default=False)
snapshot = models.ForeignKey(
'books.Snapshot',
on_delete=models.SET_NULL,
null=True,
related_name='custom_objectives'
)
def to_regular_objective(self, owner, school_class):
objective = Objective.objects.create(
owner=owner,
text=self.text,
group=self.group,
order=self.order
)
objective.visible_for.add(school_class)
objective.save()
return objective

View File

@ -47,15 +47,19 @@ class ObjectiveGroupNode(DjangoObjectType, HiddenForMixin):
def resolve_objectives(self, info, **kwargs):
user = info.context.user
school_classes = user.school_classes.values_list('pk')
base_qs = self.objectives.filter(objectivesnapshot__isnull=True)
objectives_from_publisher = Q(owner=None)
objectives_from_user = Q(owner=user)
objectives_from_teacher = Q(owner__isnull=False, visible_for__in=school_classes)
# todo
# raise NotImplemented('not in correct order')
if user.has_perm('users.can_manage_school_class_content'): # teacher
return self.objectives.filter(objectives_from_publisher | objectives_from_user)
return base_qs.filter(objectives_from_publisher | objectives_from_user)
else: # student
return self.objectives.filter(objectives_from_publisher | objectives_from_teacher)
return base_qs.filter(objectives_from_publisher | objectives_from_teacher)
class ObjectivesQuery(object):