diff --git a/.vscode/settings.json b/.vscode/settings.json index ce5a350e8f3b..a639b2850ea0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,5 +32,10 @@ "name": "cvat", "database": "${workspaceFolder:cvat}/db.sqlite3" } - ] + ], + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true } diff --git a/cvat/apps/organizations/serializers.py b/cvat/apps/organizations/serializers.py index cdcb52efaa00..f3c406750aa5 100644 --- a/cvat/apps/organizations/serializers.py +++ b/cvat/apps/organizations/serializers.py @@ -85,7 +85,8 @@ def create(self, validated_data): f'with {membership_data["user"]["email"]} email. It is not ' f'a valid email in the system.') - membership, created = Membership.objects.get_or_create(**membership_data, + membership, created = Membership.objects.get_or_create( + defaults=membership_data, user=user, organization=organization) if not created: raise serializers.ValidationError('The user is a member of ' diff --git a/tests/rest_api/assets/annotations.json b/tests/rest_api/assets/annotations.json new file mode 100644 index 000000000000..912ce1749045 --- /dev/null +++ b/tests/rest_api/assets/annotations.json @@ -0,0 +1,1437 @@ +{ + "job": { + "1": { + "shapes": [ + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 7, + "label_id": 1, + "occluded": false, + "points": [ + 249.7421875, + 432.9091796875, + 470.0352020263672, + 558.4607925415039 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 8, + "label_id": 1, + "occluded": false, + "points": [ + 416.810546875, + 226.48046875, + 560.8482818603516, + 353.5725860595703 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 6, + "label_id": 1, + "occluded": false, + "points": [ + 139.595703125, + 123.2666015625, + 348.2578582763672, + 246.5074462890625 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 1, + "group": 0, + "id": 9, + "label_id": 1, + "occluded": false, + "points": [ + 0.0, + 62.05859375, + 471.0, + 355.17291259765625 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 1, + "group": 0, + "id": 10, + "label_id": 1, + "occluded": false, + "points": [ + 0.0, + 656.4296875, + 471.0, + 827.4130401611328 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 2, + "group": 0, + "id": 11, + "label_id": 1, + "occluded": false, + "points": [ + 241.830078125, + 91.767578125, + 876.0, + 671.28369140625 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 3, + "group": 0, + "id": 12, + "label_id": 1, + "occluded": false, + "points": [ + 135.8037109375, + 264.595703125, + 470.1022644042969, + 490.49359130859375 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 5, + "group": 0, + "id": 13, + "label_id": 1, + "occluded": false, + "points": [ + 0.0, + 0.0, + 183.3411865234375, + 246.05125427246094 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 5, + "group": 0, + "id": 14, + "label_id": 1, + "occluded": false, + "points": [ + 780.04296875, + 0.0, + 979.0, + 248.173095703125 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 3 + }, + "2": { + "shapes": [ + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 1, + "label_id": 3, + "occluded": false, + "points": [ + 223.39453125, + 226.0751953125, + 513.7663269042969, + 377.9619903564453 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [], + "frame": 1, + "group": 0, + "id": 2, + "label_id": 3, + "occluded": false, + "points": [ + 63.0791015625, + 139.75390625, + 132.19337349397574, + 112.3867469879533, + 189.71144578313397, + 159.23614457831354, + 191.1030120481937, + 246.9048192771097, + 86.73554216867524, + 335.5012048192784, + 32.00060240964012, + 250.15180722891637 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 1, + "group": 0, + "id": 3, + "label_id": 4, + "occluded": false, + "points": [ + 83.0244140625, + 216.75390625, + 112.24759036144678, + 162.48313253012202, + 167.44638554216908, + 183.35662650602535, + 149.35602409638705, + 252.0072289156633, + 84.41626506024113, + 292.8265060240974, + 72.81987951807241, + 258.9650602409638 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 2, + "group": 0, + "id": 4, + "label_id": 3, + "occluded": false, + "points": [ + 24.443359375, + 107.2275390625, + 84.91109877913368, + 61.125083240844106, + 169.4316315205324, + 75.1561598224198, + 226.5581576026634, + 113.90865704772477, + 240.5892341842391, + 205.77880133185317, + 210.52264150943483, + 270.9230854605994 + ], + "rotation": 0.0, + "source": "manual", + "type": "polyline", + "z_order": 0 + }, + { + "attributes": [], + "frame": 22, + "group": 0, + "id": 5, + "label_id": 3, + "occluded": false, + "points": [ + 148.94921875, + 285.6865234375, + 313.515094339622, + 400.32830188679145, + 217.36415094339463, + 585.2339622641503, + 64.81698113207494, + 499.25283018867776 + ], + "rotation": 0.0, + "source": "manual", + "type": "points", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 3 + }, + "3": { + "shapes": [], + "tags": [], + "tracks": [], + "version": 0 + }, + "4": { + "shapes": [ + { + "attributes": [ + { + "spec_id": 1, + "value": "mazda" + } + ], + "frame": 50, + "group": 0, + "id": 22, + "label_id": 5, + "occluded": false, + "points": [ + 103.4892578125, + 60.298828125, + 319.7179412841797, + 185.8331298828125 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 1, + "value": "mazda" + } + ], + "frame": 51, + "group": 0, + "id": 23, + "label_id": 5, + "occluded": false, + "points": [ + 159.9375, + 290.716796875, + 415.7503967285156, + 440.51097106933594 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 1, + "value": "mazda" + } + ], + "frame": 52, + "group": 0, + "id": 24, + "label_id": 5, + "occluded": false, + "points": [ + 85.9462890625, + 138.1123046875, + 166.75294494628906, + 391.78382873535156 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 1, + "value": "mazda" + } + ], + "frame": 52, + "group": 0, + "id": 25, + "label_id": 5, + "occluded": false, + "points": [ + 45.03125, + 638.294921875, + 224.0333251953125, + 770.2450256347656 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + }, + { + "attributes": [ + { + "spec_id": 1, + "value": "mazda" + } + ], + "frame": 53, + "group": 0, + "id": 26, + "label_id": 5, + "occluded": false, + "points": [ + 34.384765625, + 283.845703125, + 108.30784606933594, + 382.30724334716797 + ], + "rotation": 0.0, + "source": "manual", + "type": "rectangle", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 6 + }, + "5": { + "shapes": [], + "tags": [], + "tracks": [], + "version": 0 + }, + "6": { + "shapes": [ + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 15, + "label_id": 7, + "occluded": false, + "points": [ + 50.1318359375, + 80.345703125, + 128.1219755826878, + 84.07824639289902, + 158.76792452830523, + 130.24361820200102, + 82.74239733629474, + 161.47891231964786, + 22.62918978912603, + 158.92508324084702, + 0.0, + 110.48447384849997, + 0.0, + 103.91522863219352 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 0, + "group": 0, + "id": 16, + "label_id": 7, + "occluded": false, + "points": [ + 204.34375, + 21.607421875, + 248.74128745838243, + 43.609877913431774, + 258.1708102108787, + 89.3823529411784, + 194.9144284128779, + 108.04495005549688, + 115.54927857935945, + 94.6864594894596, + 93.35061043285532, + 50.28912319645133, + 107.69134295227741, + 33.39456159822657 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 1, + "group": 0, + "id": 17, + "label_id": 7, + "occluded": false, + "points": [ + 79.9326171875, + 54.205078125, + 81.22958500669301, + 50.313253012047426, + 84.4725568942431, + 47.93507362784476, + 88.79651941097654, + 45.98929049531398, + 92.03949129852663, + 44.90829986613062, + 96.36345381526007, + 43.61111111111131, + 100.03882195448386, + 42.7463186077639, + 106.30856760374809, + 40.80053547523312, + 113.44310575635791, + 38.85475234270416, + 118.63186077643877, + 37.557563587683035, + 124.03681392235558, + 36.26037483266373, + 128.5769745649268, + 35.39558232931631, + 132.03614457831281, + 34.74698795180666, + 135.92771084337255, + 34.098393574297006, + 142.62985274431048, + 33.6659973226233, + 147.17001338687987, + 33.6659973226233, + 153.0073627844704, + 33.88219544846106, + 160.79049531459168, + 34.530789825970714, + 165.33065595716107, + 34.96318607764442, + 171.38420348058935, + 35.611780455154076, + 175.7081659973228, + 36.044176706827784, + 180.46452476572995, + 36.69277108433744, + 184.13989290495374, + 37.557563587683035, + 189.11244979919684, + 37.98995983935674, + 193.65261044176623, + 38.42235609103045, + 197.32797858099002, + 39.070950468540104, + 200.35475234270416, + 40.36813922356123, + 204.6787148594376, + 42.96251673360166, + 209.43507362784476, + 45.55689424364027, + 213.54283801874226, + 47.93507362784476, + 217.434404283802, + 50.745649263721134, + 220.67737617135208, + 54.20481927710898, + 223.70414993306622, + 57.01539491298536, + 227.16331994645225, + 60.69076305220915, + 231.70348058902164, + 65.0147255689426, + 237.10843373494026, + 71.06827309236905, + 242.51338688085707, + 76.90562248995957, + 247.26974564926422, + 82.52677376171414, + 250.5127175368143, + 88.36412315930284, + 252.02610441766956, + 92.25568942436439, + 253.10709504685292, + 96.14725568942413, + 254.40428380187404, + 100.68741633199352, + 255.26907630522146, + 108.25435073627887, + 255.26907630522146, + 112.36211512717455, + 254.83668005354775, + 116.90227576974576, + 253.7556894243644, + 121.2262382864792, + 252.89089692101697, + 124.901606425703, + 251.3775100401599, + 129.44176706827238, + 249.21552878179318, + 133.54953145916988, + 246.83734939759051, + 137.0087014725559, + 243.37817938420267, + 140.03547523427005, + 237.75702811244992, + 143.9270414993298, + 230.62248995983828, + 147.38621151271764, + 225.43373493975923, + 149.3319946452466, + 221.1097724230258, + 150.196787148594, + 216.56961178045458, + 150.62918340026772, + 212.0294511378852, + 150.84538152610367, + 206.40829986613062, + 151.27777777777737, + 200.1385542168664, + 151.71017402945108, + 193.43641231593028, + 152.35876840696073, + 188.89625167335907, + 152.35876840696073, + 181.5455153949133, + 152.35876840696073, + 177.22155287817986, + 152.35876840696073, + 171.6004016064253, + 152.57496653279668, + 165.76305220883478, + 152.57496653279668, + 161.65528781793728, + 152.1425702811248, + 156.46653279785824, + 151.71017402945108, + 147.38621151271764, + 150.41298527442996, + 136.79250334671997, + 147.81860776439134, + 132.46854082998652, + 146.52141900937022, + 126.1987951807223, + 143.9270414993298, + 121.65863453815291, + 141.54886211512712, + 115.60508701472463, + 138.73828647925075, + 109.76773761713412, + 135.7115127175366, + 106.95716198125774, + 133.9819277108436, + 103.93038821954542, + 130.95515394912945, + 100.68741633199352, + 124.25301204819334, + 97.22824631860749, + 118.19946452476506, + 94.20147255689335, + 112.1459170013386, + 92.25568942436439, + 106.95716198125774, + 90.09370816599767, + 102.6331994645243, + 87.28313253011947, + 98.9578313253005, + 85.76974564926422, + 95.06626506024077, + 82.52677376171414, + 91.82329317269068, + 79.06760374832629, + 88.79651941097654, + 74.5274431057569, + 85.98594377510017, + 69.9872824631857, + 84.68875502008086, + 65.0147255689426, + 84.4725568942431, + 59.60977242302579, + 86.41834002677388, + 56.15060240963794, + 88.14792503346689, + 52.90763052208786, + 89.8775100401599, + 49.88085676037372, + 91.82329317269068, + 47.07028112449734, + 93.9852744310574, + 42.31392235609019, + 97.01204819277154, + 37.98995983935674, + 99.17402945113827, + 34.530789825970714, + 100.25502008032163, + 30.855421686746922, + 98.5254350736268, + 28.6934404283802, + 95.06626506024077, + 25.882864792503824, + 87.71552878179318, + 24.5856760374827, + 82.74297188755008, + 22.63989290495374, + 74.95983935742879, + 21.342704149932615, + 69.33868808567604, + 19.829317269075545, + 63.28514056224958, + 19.180722891565892, + 59.17737617135208, + 18.315930388218476, + 54.63721552878087, + 17.883534136546587, + 50.52945113788519, + 17.883534136546587, + 44.692101740294675, + 17.883534136546587, + 39.070950468540104, + 18.964524765729948, + 33.88219544846106, + 19.396921017401837, + 28.909638554216144, + 19.829317269075545, + 25.018072289156407, + 21.775100401606323, + 20.694109772422962, + 23.937081659973046, + 16.58634538152546, + 26.09906291833977, + 13.559571619813141, + 28.26104417670649, + 10.748995983934947, + 31.071619812582867, + 8.803212851405988, + 35.17938420348037, + 7.722222222222626, + 41.23293172690683, + 7.506024096384863, + 48.58366800535441, + 9.235609103077877, + 53.55622489959751, + 10.96519410977271, + 57.447791164659066, + 12.47858099062978, + 62.420348058902164, + 14.424364123158739, + 66.52811244979966, + 16.370147255689517, + 69.33868808567604, + 18.53212851405624, + 74.95983935742879, + 23.7208835341371, + 77.77041499330699, + 26.531459170013477, + 80.7971887550193, + 30.423025435073214, + 82.52677376171414, + 34.74698795180666, + 83.39156626505974, + 38.85475234270416, + 83.6077643908975, + 42.097724230254244, + 82.52677376171414, + 45.55689424364027 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 2, + "group": 0, + "id": 18, + "label_id": 7, + "occluded": false, + "points": [ + 280.2734375, + 143.0498046875, + 298.8688085676058, + 139.20214190093975, + 311.693440428382, + 137.91967871486122, + 333.4953145917025, + 136.6372155287845, + 352.09103078982844, + 136.6372155287845, + 371.32797858099366, + 136.6372155287845, + 391.8473895582356, + 136.6372155287845, + 405.31325301205106, + 136.6372155287845, + 427.1151271753697, + 135.99598393574524, + 448.2757697456509, + 135.99598393574524, + 470.07764390897137, + 135.99598393574524, + 484.1847389558261, + 134.7135207496667, + 502.78045515395206, + 134.7135207496667, + 529.0709504685437, + 134.07228915662927, + 545.1017402945145, + 134.7135207496667, + 589.9879518072303, + 138.56091030790049, + 613.0722891566293, + 140.48460508701646, + 626.5381526104447, + 141.12583668005573, + 637.4390896921032, + 141.767068273095, + 650.2637215528812, + 143.0495314591717, + 668.8594377510071, + 144.9732262382895, + 681.0428380187441, + 145.61445783132694, + 707.974564926375, + 148.82061579652145, + 718.8755020080353, + 150.10307898259998, + 729.1352074966562, + 151.3855421686767, + 738.7536813922379, + 153.30923694779267, + 753.5020080321301, + 157.7978580990657, + 768.2503346720241, + 163.56894243641364, + 783.6398929049556, + 172.5461847389579, + 790.693440428382, + 179.59973226238435, + 795.8232931726925, + 187.93574297188934, + 797.7469879518103, + 200.76037483266555, + 797.7469879518103, + 216.149933065597, + 786.8460508701501, + 227.6921017402965, + 777.8688085676058, + 232.1807228915677, + 759.9143239625191, + 236.66934404284075, + 747.0896921017429, + 237.3105756358782, + 734.9062918340042, + 237.95180722891746, + 716.3105756358782, + 238.59303882195672, + 697.0736278447148, + 239.234270414996, + 675.9129852744336, + 239.87550200803344, + 654.7523427041524, + 240.5167336010727, + 640.0040160642584, + 240.5167336010727, + 619.4846050870165, + 239.234270414996, + 606.6599732262403, + 238.59303882195672, + 584.2168674698823, + 238.59303882195672, + 572.6746987951828, + 239.234270414996, + 560.4912985274459, + 239.234270414996, + 548.9491298527464, + 238.59303882195672, + 536.1244979919702, + 237.3105756358782, + 521.376171352078, + 236.02811244980148, + 506.627844712184, + 234.74564926372295, + 490.5970548862133, + 233.46318607764624, + 477.1311914323978, + 233.46318607764624, + 457.25301204819516, + 232.82195448460698, + 441.22222222222445, + 232.1807228915677, + 419.420348058904, + 232.1807228915677, + 391.8473895582356, + 232.1807228915677, + 377.0990629183416, + 232.1807228915677, + 362.3507362784494, + 232.1807228915677, + 346.96117804551795, + 232.82195448460698, + 331.5716198125865, + 234.1044176706855, + 316.8232931726925, + 236.02811244980148, + 295.6626506024113, + 242.44042838018868, + 286.0441767068296, + 246.92904953146171, + 272.57831325301413, + 255.2650602409667, + 264.8835341365484, + 262.31860776439316, + 257.82998661312195, + 276.4257028112479, + 256.5475234270434, + 288.60910307898484, + 256.5475234270434, + 303.9986613119163, + 259.7536813922379, + 318.10575635877103, + 266.1659973226251, + 326.441767068276, + 273.86077643909266, + 334.7777777777792, + 290.5327978581008, + 346.3199464524787, + 302.0749665328003, + 351.4497991967892, + 320.029451137887, + 355.9384203480604, + 340.54886211512894, + 359.1445783132549, + 359.78580990629416, + 360.4270414993334, + 370.6867469879544, + 361.70950468541014, + 388.6412315930411, + 361.70950468541014, + 418.77911646586654, + 364.91566265060465, + 436.09236947791396, + 366.8393574297206, + 461.1004016064271, + 369.40428380187586, + 480.9785809906316, + 371.32797858099366, + 497.0093708166023, + 373.25167336010963, + 512.3989290495338, + 376.45783132530414, + 529.0709504685437, + 379.0227576974594, + 545.7429718875519, + 382.22891566265207, + 566.2623828647938, + 384.7938420348073, + 582.2931726907645, + 387.35876840696255, + 596.4002677376193, + 388.6412315930411, + 607.9424364123188, + 390.56492637215706, + 619.4846050870165, + 392.48862115127304, + 636.7978580990657, + 398.90093708166205, + 647.0575635876867, + 401.4658634538173, + 656.0348058902291, + 411.084337349399, + 659.2409638554236, + 421.3440428380218, + 660.5234270415021, + 434.80990629183543, + 659.8821954484629, + 450.84069611780615, + 654.1111111111131, + 460.45917001338967, + 638.7215528781817, + 470.07764390897137, + 618.843373493979, + 474.5662650602426, + 609.2248995983955, + 475.8487282463211, + 592.5528781793855, + 475.8487282463211, + 570.1097724230276, + 475.8487282463211, + 551.5140562249017, + 475.8487282463211, + 538.6894243641254, + 475.8487282463211, + 511.7576974564945, + 475.8487282463211, + 493.8032128514078, + 474.5662650602426, + 478.41365461847636, + 474.5662650602426, + 464.9477911646609, + 474.5662650602426, + 451.4819277108454, + 474.5662650602426, + 434.80990629183543, + 474.5662650602426, + 420.06157965194325, + 474.5662650602426, + 400.1834002677406, + 473.92503346720514, + 384.15261044176987, + 473.2838018741659, + 373.8929049531489, + 473.2838018741659, + 357.8621151271782, + 472.00133868808734, + 335.41900937081846, + 470.07764390897137, + 325.80053547523676, + 468.1539491298554, + 305.92235609103227, + 464.9477911646609, + 291.1740294511401, + 463.0240963855449, + 277.7081659973246, + 460.45917001338967, + 267.44846050870365, + 457.8942436412344, + 250.13520749665622, + 453.4056224899614, + 236.66934404284075, + 448.91700133869017, + 225.76840696118052, + 444.42838018741895, + 214.22623828648102, + 439.29852744310847, + 199.47791164658884, + 430.9625167336035, + 187.29451137885007, + 425.832663989293, + 173.18741633199716, + 416.85542168674874, + 162.9277108433762, + 408.51941097724375, + 153.95046854083193, + 399.5421686747013, + 146.89692101740548, + 391.2061579651963, + 140.48460508701646, + 382.22891566265207, + 135.35475234270598, + 370.0455153949151, + 129.58366800535623, + 354.6559571619837, + 125.09504685408501, + 339.26639892905223, + 120.6064257028138, + 319.38821954484774, + 118.68273092369782, + 309.76974564926604, + 114.19410977242478, + 296.94511378848983, + 110.34672021419283, + 284.7617135207511, + 104.57563587684308, + 271.2958500669374, + 92.39223560910432, + 244.36412315930647, + 84.6974564926386, + 228.97456492637502, + 77.64390896921213, + 212.9437751004043, + 71.23159303882494, + 193.7068273092391, + 65.46050870147519, + 177.67603748326837, + 62.254350736280685, + 162.28647925033692, + 60.33065595716471, + 149.46184738956072, + 59.04819277108618, + 132.14859437751147, + 58.40696117804691, + 118.04149933065855, + 58.40696117804691, + 103.29317269076455, + 59.04819277108618, + 92.39223560910432, + 60.971887550202155, + 78.2851405622514, + 63.536813922357396, + 65.46050870147519, + 66.10174029451264, + 52.635876840698984, + 69.30789825970714, + 43.017402945115464, + 76.36144578313542, + 32.7576974564945, + 87.9036144578331, + 21.856760374834266, + 97.52208835341662, + 16.085676037484518, + 109.0642570281143, + 12.238286479252565, + 125.09504685408501, + 9.673360107097324, + 137.91967871486122, + 9.673360107097324, + 150.10307898259998, + 12.238286479252565, + 161.0040160642584, + 18.65060240964158, + 170.62248995984191, + 31.475234270417786, + 176.39357429719166, + 41.73493975903875, + 180.24096385542362, + 57.1244979919702, + 182.1646586345396, + 71.87282463186239, + 182.80589022757886, + 89.18607764391163, + 180.88219544846288, + 103.29317269076455, + 178.9585006693469, + 115.47657295850331, + 177.0348058902291, + 127.65997322624025, + 175.11111111111313, + 138.56091030790049, + 173.18741633199716, + 150.74431057563743, + 173.18741633199716, + 166.77510040160814, + 176.39357429719166, + 181.52342704150215, + 182.1646586345396, + 192.42436412316056, + 191.14190093708385, + 203.3253012048208, + 200.76037483266555, + 207.81392235609383, + 211.0200803212865, + 202.68406961178334, + 224.485943775102, + 187.29451137885007, + 230.898259705491, + 175.11111111111313, + 235.38688085676222, + 154.5917001338712, + 236.66934404284075, + 137.27844712182196, + 236.66934404284075, + 118.68273092369782, + 234.74564926372295, + 107.78179384203759, + 232.82195448460698, + 92.39223560910432, + 230.25702811245174, + 79.56760374832811, + 229.61579651941247, + 68.6666666666697, + 228.97456492637502, + 57.76572958500947, + 230.25702811245174, + 47.5060240963885, + 235.38688085676222, + 36.60508701472827, + 248.8527443105777, + 34.681392235610474, + 259.7536813922379, + 40.45247657296022, + 269.3721552878196, + 45.582329317270705, + 277.7081659973246, + 51.99464524765972, + 283.47925033467436, + 60.33065595716471, + 283.47925033467436, + 72.51405622490165, + 282.19678714859583, + 82.77376171352262, + 278.3493975903639, + 93.67469879518285, + 276.4257028112479, + 103.29317269076455, + 275.1432396251694, + 113.55287817938552, + 276.4257028112479, + 123.17135207496904 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 3, + "group": 0, + "id": 20, + "label_id": 7, + "occluded": false, + "points": [ + 40.9013671875, + 278.5703125, + 49.74472807990969, + 274.7014428412858, + 60.7991120976676, + 272.4905660377335, + 69.08990011098649, + 271.9378468368468, + 80.69700332963293, + 271.38512763595827, + 92.30410654827756, + 271.38512763595827, + 110.54384017757911, + 272.4905660377335, + 122.70366259711227, + 274.1487236403973, + 140.3906770255253, + 279.67591564927716, + 152.55049944506027, + 284.6503884572685, + 163.05216426192965, + 297.9156492785769, + 170.23751387347147, + 306.2064372918958, + 179.63374028856742, + 316.15538290787845, + 185.713651498334, + 327.20976692563636, + 188.47724750277303, + 336.6059933407305, + 189.58268590454827, + 348.21309655937694, + 187.9245283018845, + 358.1620421753596, + 184.05549389567022, + 367.0055493895652, + 176.31742508323987, + 379.7180910099869, + 166.3684794672572, + 388.5615982241943, + 156.41953385127454, + 395.1942286348494, + 144.25971143174138, + 401.274139844616, + 130.99445061043116, + 406.24861265260733, + 116.62375138734569, + 410.1176470588216, + 103.911209766924, + 409.5649278579349, + 94.51498335182987, + 402.37957824639125, + 86.22419533851098, + 393.53607103218565, + 77.38068812430538, + 383.03440621531445, + 71.30077691453698, + 369.2164261931175, + 64.66814650388369, + 355.39844617091876, + 59.69367369589236, + 344.8967813540494, + 56.930077691451515, + 336.6059933407305, + 55.82463928967627, + 328.3152053274116, + 56.3773584905648, + 317.2608213096537, + 58.58823529411529, + 308.9700332963366, + 56.930077691451515, + 299.57380688124067, + 51.40288568257347, + 292.9411764705874, + 44.77025527191836, + 287.4139844617075, + 37.584905660376535, + 282.4395116537162 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 3, + "group": 0, + "id": 21, + "label_id": 7, + "occluded": false, + "points": [ + 106.1220703125, + 302.8896484375, + 96.72586015538218, + 305.10099889012054, + 88.43507214206329, + 303.9955604883453, + 80.1442841287444, + 307.86459489455956, + 72.40621531631405, + 315.0499445061032, + 68.53718091009796, + 323.8934517203088, + 67.98446170921125, + 334.9478357380667, + 77.38068812430538, + 344.34406215316085, + 85.67147613762245, + 346.0022197558246, + 95.0677025527184, + 347.6603773584884, + 107.78024417314009, + 351.5294117647045, + 116.62375138734569, + 353.7402885682568, + 124.91453940066458, + 352.082130965593, + 132.0998890122064, + 345.4495005549379, + 139.83795782463858, + 337.71143174250756, + 145.36514983351663, + 327.7624861265249, + 148.12874583795565, + 318.36625971143076, + 141.49611542730054, + 312.28634850166236, + 133.20532741398347, + 308.9700332963366, + 124.91453940066458, + 305.65371809100907, + 117.72918978912094, + 301.23196448390445 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + }, + { + "attributes": [], + "frame": 3, + "group": 0, + "id": 19, + "label_id": 7, + "occluded": false, + "points": [ + 72.185546875, + 29.8466796875, + 26.30943396226212, + 62.45726970033138, + 26.30943396226212, + 71.30077691453698, + 26.30943396226212, + 82.35516093229671, + 27.414872364039184, + 93.40954495005462, + 29.625749167589674, + 102.80577136514876, + 32.3893451720287, + 111.64927857935436, + 40.12741398446087, + 118.834628190898, + 50.62907880133025, + 122.70366259711227, + 69.42153163151852, + 123.2563817980008, + 86.55582685904483, + 123.2563817980008, + 98.16293007768945, + 123.2563817980008, + 111.42819089899967, + 123.80910099888933, + 123.03529411764612, + 122.70366259711227, + 135.7478357380678, + 121.04550499444849, + 145.69678135404865, + 117.17647058823422, + 154.54028856825607, + 111.64927857935436, + 162.27835738068643, + 103.911209766924, + 166.14739178690252, + 95.62042175360511, + 168.91098779134154, + 87.32963374028623, + 172.2273029966691, + 79.03884572696916, + 174.99089900110812, + 70.19533851276174, + 176.09633740288336, + 61.351831298556135, + 175.54361820199665, + 52.508324084348715, + 177.20177580466043, + 43.66481687014311, + 183.281687014427, + 34.82130965593569, + 201.52142064372674, + 20.450610432850226, + 195.44150943396016, + 14.370699223083648, + 187.7034406215298, + 9.948945615980847, + 176.09633740288336, + 6.079911209764759, + 167.8055493895663, + 3.3163152053257363, + 157.85660377358363, + 1.6581576026619587, + 146.80221975582572, + 1.1054384017734264, + 134.64239733629074, + 0.5527192008867132, + 122.48257491675759, + 1.1054384017734264, + 112.53362930077492, + 2.763596004437204, + 103.69012208656932, + 4.974472807989514, + 94.29389567147518, + 7.738068812428537, + 86.55582685904483, + 12.159822419533157, + 77.71231964483741, + 17.13429522752267 + ], + "rotation": 0.0, + "source": "manual", + "type": "polygon", + "z_order": 0 + } + ], + "tags": [], + "tracks": [], + "version": 3 + } + } +} \ No newline at end of file diff --git a/tests/rest_api/conftest.py b/tests/rest_api/conftest.py index 640eb9260423..1ca201a62496 100644 --- a/tests/rest_api/conftest.py +++ b/tests/rest_api/conftest.py @@ -50,27 +50,69 @@ def init_test_db(): def restore(): restore_cvat_db() +class Container: + def __init__(self, data, key='id'): + self.raw_data = data + self.map_data = { obj[key]: obj for obj in data } + + @property + def raw(self): + return self.raw_data + + @property + def map(self): + return self.map_data + + def __iter__(self): + return iter(self.raw_data) + + def __len__(self): + return len(self.raw_data) + + def __getitem__(self, key): + if isinstance(key, slice): + return self.raw_data[key] + return self.map_data[key] + @pytest.fixture(scope='module') def users(): with open(osp.join(ASSETS_DIR, 'users.json')) as f: - return json.load(f)['results'] + return Container(json.load(f)['results']) @pytest.fixture(scope='module') def organizations(): with open(osp.join(ASSETS_DIR, 'organizations.json')) as f: - data = json.load(f) - - def _organizations(org_id=None): - if org_id: - return [org for org in data if org['id'] == org_id][0] - return data - - return _organizations + return Container(json.load(f)) @pytest.fixture(scope='module') def memberships(): with open(osp.join(ASSETS_DIR, 'memberships.json')) as f: - return json.load(f)['results'] + return Container(json.load(f)['results']) + +@pytest.fixture(scope='module') +def tasks(): + with open(osp.join(ASSETS_DIR, 'tasks.json')) as f: + return Container(json.load(f)['results']) + +@pytest.fixture(scope='module') +def projects(): + with open(osp.join(ASSETS_DIR, 'projects.json')) as f: + return Container(json.load(f)['results']) + +@pytest.fixture(scope='module') +def jobs(): + with open(osp.join(ASSETS_DIR, 'jobs.json')) as f: + return Container(json.load(f)['results']) + +@pytest.fixture(scope='module') +def invitations(): + with open(osp.join(ASSETS_DIR, 'invitations.json')) as f: + return Container(json.load(f)['results'], key='key') + +@pytest.fixture(scope='module') +def annotations(): + with open(osp.join(ASSETS_DIR, 'annotations.json')) as f: + return json.load(f) @pytest.fixture(scope='module') def users_by_name(users): @@ -116,7 +158,3 @@ def add_row(**kwargs): membership_id=membership['id']) return data - - - - diff --git a/tests/rest_api/test_0000_check_objects_integrity.py b/tests/rest_api/test_0000_check_objects_integrity.py index 239bfbb00839..d75a9092677c 100644 --- a/tests/rest_api/test_0000_check_objects_integrity.py +++ b/tests/rest_api/test_0000_check_objects_integrity.py @@ -13,9 +13,15 @@ def test_check_objects_integrity(path): with open(path) as f: endpoint = osp.basename(path).rsplit('.')[0] - response = config.get_method('admin1', endpoint, page_size='all') - json_objs = json.load(f) - resp_objs = response.json() + if endpoint == 'annotations': + objects = json.load(f) + for jid, annotations in objects['job'].items(): + response = config.get_method('admin1', f'jobs/{jid}/annotations').json() + assert DeepDiff(annotations, response, ignore_order=True) == {} + else: + response = config.get_method('admin1', endpoint, page_size='all') + json_objs = json.load(f) + resp_objs = response.json() - assert DeepDiff(json_objs, resp_objs, ignore_order=True, - exclude_regex_paths="root\['results'\]\[\d+\]\['last_login'\]") == {} + assert DeepDiff(json_objs, resp_objs, ignore_order=True, + exclude_regex_paths="root\['results'\]\[\d+\]\['last_login'\]") == {} diff --git a/tests/rest_api/test_0001_users.py b/tests/rest_api/test_0001_users.py index c530cdf8c8c9..7fbccd4d5b96 100644 --- a/tests/rest_api/test_0001_users.py +++ b/tests/rest_api/test_0001_users.py @@ -24,7 +24,7 @@ def _test_cannot_see(self, user, endpoint='users', **kwargs): def test_admin_can_see_all_others(self, users): exclude_paths = [f"root[{i}]['last_login']" for i in range(len(users))] - self._test_can_see('admin2', users, exclude_paths=exclude_paths, + self._test_can_see('admin2', users.raw, exclude_paths=exclude_paths, page_size="all") def test_everybody_can_see_self(self, users_by_name): diff --git a/tests/rest_api/test_0002_organizations.py b/tests/rest_api/test_0002_organizations.py index 4ff632145226..8e5a9ac1cf37 100644 --- a/tests/rest_api/test_0002_organizations.py +++ b/tests/rest_api/test_0002_organizations.py @@ -30,7 +30,7 @@ def test_can_see_specific_organization(self, privilege, role, is_member, response = get_method(user, f'organizations/{self._ORG}') if is_allow: assert response.status_code == HTTPStatus.OK - assert DeepDiff(organizations(self._ORG), response.json()) == {} + assert DeepDiff(organizations[self._ORG], response.json()) == {} else: assert response.status_code == HTTPStatus.NOT_FOUND @@ -44,7 +44,7 @@ def request_data(self): @pytest.fixture(scope='class') def expected_data(self, organizations, request_data): - data = organizations(self._ORG).copy() + data = organizations[self._ORG].copy() data.update(request_data) return data diff --git a/tests/rest_api/test_0003_membership.py b/tests/rest_api/test_0003_membership.py index 4c6086acdf0f..492b63e990a6 100644 --- a/tests/rest_api/test_0003_membership.py +++ b/tests/rest_api/test_0003_membership.py @@ -21,16 +21,17 @@ def _test_cannot_see_memberships(self, user, **kwargs): assert response.status_code == HTTPStatus.FORBIDDEN def test_admin_can_see_all_memberships(self, memberships): - self._test_can_see_memberships('admin2', memberships, page_size='all') + self._test_can_see_memberships('admin2', memberships.raw, page_size='all') def test_non_admin_can_see_only_self_memberships(self, memberships): non_admins= ['business1', 'user1', 'dummy1','worker2'] - for user in non_admins: - data = [m for m in memberships if m['user']['username'] == user] - self._test_can_see_memberships(user, data) + for username in non_admins: + data = [obj for obj in memberships + if obj['user']['username'] == username] + self._test_can_see_memberships(username, data) def test_all_members_can_see_other_members_membership(self, memberships): - data = [m for m in memberships if m['organization'] == 1] + data = [obj for obj in memberships if obj['organization'] == 1] for membership in data: self._test_can_see_memberships(membership['user']['username'], data, org_id=1) diff --git a/tests/rest_api/test_0050_invitations.py b/tests/rest_api/test_0050_invitations.py new file mode 100644 index 000000000000..fde4c243c165 --- /dev/null +++ b/tests/rest_api/test_0050_invitations.py @@ -0,0 +1,72 @@ +# Copyright (C) 2021 Intel Corporation +# +# SPDX-License-Identifier: MIT + +from http import HTTPStatus +import pytest +from .utils.config import post_method + +class TestCreateInvitations: + def _test_post_invitation_201(self, user, data, invitee, **kwargs): + response = post_method(user, 'invitations', data, **kwargs) + + assert response.status_code == HTTPStatus.CREATED + assert data['role'] == response.json()['role'] + assert invitee['id'] == response.json()['user']['id'] + assert kwargs['org_id'] == response.json()['organization'] + + def _test_post_invitation_403(self, user, data, **kwargs): + response = post_method(user, 'invitations', data, **kwargs) + assert response.status_code == HTTPStatus.FORBIDDEN + + @staticmethod + def get_non_member_users(memberships, users): + organization_users = set(m['user']['id'] for m in memberships if m['user'] != None) + non_member_users = [u for u in users if u['id'] not in organization_users] + + return non_member_users + + @staticmethod + def get_member(role, memberships, org_id): + member = [m['user'] for m in memberships if m['role'] == role and + m['organization'] == org_id and m['user'] != None][0] + + return member + + @pytest.mark.parametrize('org_id', [2]) + @pytest.mark.parametrize('org_role', ['worker', 'supervisor', 'maintainer', 'owner']) + def test_create_invitation(self, organizations, memberships, users, + org_id, org_role): + member = self.get_member(org_role, memberships, org_id) + non_member_users = self.get_non_member_users(memberships, users) + + if org_role in ['worker', 'supervisor']: + for invitee_role in ['worker', 'supervisor', 'maintainer', 'owner']: + self._test_post_invitation_403(member['username'], { + 'role': invitee_role, + 'email': non_member_users[0]['email'] + }, org_id=org_id) + else: + for idx, invitee_role in enumerate(['worker', 'supervisor']): + self._test_post_invitation_201(member['username'], { + 'role': invitee_role, + 'email': non_member_users[idx]['email'] + }, non_member_users[idx], org_id=org_id) + + # only the owner can invite a maintainer + if org_role == 'owner': + self._test_post_invitation_201(member['username'], { + 'role': 'maintainer', + 'email': non_member_users[2]['email'] + }, non_member_users[2], org_id=org_id) + else: + self._test_post_invitation_403(member['username'], { + 'role': 'maintainer', + 'email': non_member_users[3]['email'] + }, org_id=org_id) + + # nobody can invite an owner + self._test_post_invitation_403(member['username'], { + 'role': 'owner', + 'email': non_member_users[4]['email'] + }, org_id=org_id) diff --git a/tests/rest_api/test_0100_jobs.py b/tests/rest_api/test_0100_jobs.py new file mode 100644 index 000000000000..887d768cbb6a --- /dev/null +++ b/tests/rest_api/test_0100_jobs.py @@ -0,0 +1,170 @@ +# Copyright (C) 2021 Intel Corporation +# +# SPDX-License-Identifier: MIT + +from http import HTTPStatus +from deepdiff import DeepDiff +import pytest +from .utils.config import get_method + +def get_job_staff(job, tasks, projects): + job_staff = [] + job_staff.append(job['assignee']) + tid = job['task_id'] + job_staff.append(tasks[tid]['owner']) + job_staff.append(tasks[tid]['assignee']) + + pid = job['project_id'] + if pid: + job_staff.append(projects[pid]['owner']) + job_staff.append(projects[pid]['assignee']) + job_staff = set(u['id'] for u in job_staff if u is not None) + + return job_staff + +def get_org_staff(org_id, memberships): + if org_id in ['', None]: + return set() + else: + return set(m['user']['id'] for m in memberships + if m['role'] in ['maintainer', 'owner'] and m['user'] != None + and m['organization'] == org_id) + +def filter_jobs(jobs, tasks, org): + if org is None: + kwargs = {} + jobs = jobs.raw + elif org == '': + kwargs = {'org': ''} + jobs = [job for job in jobs + if tasks[job['task_id']]['organization'] is None] + else: + kwargs = {'org_id': org} + jobs = [job for job in jobs + if tasks[job['task_id']]['organization'] == org] + + return jobs, kwargs + +def is_org_member(memberships, user, org_id): + if org_id in ['', None]: + return True + else: + return user['id'] in set(m['user']['id'] for m in memberships + if m['user'] != None and m['organization'] == org_id) + +class TestGetJobs: + def _test_get_job_200(self, user, jid, data, **kwargs): + response = get_method(user, f'jobs/{jid}', **kwargs) + + assert response.status_code == HTTPStatus.OK + assert DeepDiff(data, response.json()) == {} + + def _test_get_job_403(self, user, jid, **kwargs): + response = get_method(user, f'jobs/{jid}', **kwargs) + assert response.status_code == HTTPStatus.FORBIDDEN + + @pytest.mark.parametrize('org', [None, '', 1, 2]) + def test_admin_get_job(self, jobs, tasks, org): + jobs, kwargs = filter_jobs(jobs, tasks, org) + + # keep only the reasonable amount of jobs + for job in jobs[:8]: + self._test_get_job_200('admin2', job['id'], job, **kwargs) + + @pytest.mark.parametrize('org_id', ['', None, 1, 2]) + @pytest.mark.parametrize('groups', [['business'], ['user'], ['worker'], []]) + def test_non_admin_get_job(self, org_id, groups, users, jobs, tasks, projects, + memberships): + # keep the reasonable amount of users and jobs + users = [u for u in users if u['groups'] == groups][:4] + jobs, kwargs = filter_jobs(jobs, tasks, org_id) + org_staff = get_org_staff(org_id, memberships) + + for job in jobs[:8]: + job_staff = get_job_staff(job, tasks, projects) + + # check if the specific user in job_staff to see the job + for user in users: + if user['id'] in job_staff | org_staff: + self._test_get_job_200(user['username'], job['id'], job, **kwargs) + else: + self._test_get_job_403(user['username'], job['id'], **kwargs) + +class TestListJobs: + def _test_list_jobs_200(self, user, data, **kwargs): + response = get_method(user, 'jobs', **kwargs, page_size=all) + + assert response.status_code == HTTPStatus.OK + assert DeepDiff(data, response.json()['results']) == {} + + def _test_list_jobs_403(self, user, **kwargs): + response = get_method(user, 'jobs', **kwargs) + assert response.status_code == HTTPStatus.FORBIDDEN + + @pytest.mark.parametrize('org', [None, '', 1, 2]) + def test_admin_list_jobs(self, jobs, tasks, org): + jobs, kwargs = filter_jobs(jobs, tasks, org) + self._test_list_jobs_200('admin1', jobs, **kwargs) + + @pytest.mark.parametrize('org_id', ['', None, 1, 2]) + @pytest.mark.parametrize('groups', [['business'], ['user'], ['worker'], []]) + def test_non_admin_list_jobs(self, org_id, groups, users, jobs, tasks, + projects, memberships): + # keep the reasonable amount of users and jobs + users = [u for u in users if u['groups'] == groups][:2] + jobs, kwargs = filter_jobs(jobs, tasks, org_id) + org_staff = get_org_staff(org_id, memberships) + + for user in users: + user_jobs = [] + for job in jobs: + job_staff = get_job_staff(job, tasks, projects) + if user['id'] in job_staff | org_staff: + user_jobs.append(job) + if is_org_member(memberships, user, org_id): + self._test_list_jobs_200(user['username'], user_jobs, **kwargs) + else: + self._test_list_jobs_403(user['username'], **kwargs) + + +class TestGetAnnotations: + def _test_get_job_annotations_200(self, user, jid, data, **kwargs): + response = get_method(user, f'jobs/{jid}/annotations', **kwargs) + + assert response.status_code == HTTPStatus.OK + assert DeepDiff(data, response.json()) == {} + + def _test_get_job_annotations_403(self, user, jid, **kwargs): + response = get_method(user, f'jobs/{jid}/annotations', **kwargs) + assert response.status_code == HTTPStatus.FORBIDDEN + + @pytest.mark.parametrize('org', [None, '', 1, 2]) + def test_admin_get_job_annotations(self, jobs, tasks, annotations, org): + jobs, kwargs = filter_jobs(jobs, tasks, org) + + # keep only the reasonable amount of jobs + for job in jobs[:8]: + jid = str(job['id']) + self._test_get_job_annotations_200('admin2', jid, + annotations['job'][jid], **kwargs) + + @pytest.mark.parametrize('org_id', ['', None]) + @pytest.mark.parametrize('groups', [['business'], ['user'], ['worker'], []]) + def test_non_admin_get_job_annotations(self, org_id, groups, users, jobs, tasks, + projects, annotations, memberships): + users = [u for u in users if u['groups'] == groups][:4] + jobs, kwargs = filter_jobs(jobs, tasks, org_id) + org_staff = get_org_staff(org_id, memberships) + + # keep only the reasonable amount of jobs + for job in jobs[:8]: + job_staff = get_job_staff(job, tasks, projects) + jid = str(job['id']) + + for user in users: + if user['id'] in job_staff | org_staff: + self._test_get_job_annotations_200(user['username'], + jid, annotations['job'][jid], **kwargs) + else: + self._test_get_job_annotations_403(user['username'], + jid, **kwargs) diff --git a/tests/rest_api/utils/config.py b/tests/rest_api/utils/config.py index 057389fda407..ff47733d4ea7 100644 --- a/tests/rest_api/utils/config.py +++ b/tests/rest_api/utils/config.py @@ -21,4 +21,7 @@ def delete_method(username, endpoint, **kwargs): return requests.delete(get_api_url(endpoint, **kwargs), auth=(username, USER_PASS)) def patch_method(username, endpoint, data, **kwargs): - return requests.patch(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) \ No newline at end of file + return requests.patch(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) + +def post_method(username, endpoint, data, **kwargs): + return requests.post(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) \ No newline at end of file diff --git a/tests/rest_api/utils/dump_objects.py b/tests/rest_api/utils/dump_objects.py index 2f1e2166b86d..c7e566457ea7 100644 --- a/tests/rest_api/utils/dump_objects.py +++ b/tests/rest_api/utils/dump_objects.py @@ -2,8 +2,19 @@ from config import get_method, ASSETS_DIR import json +annotations = {} for obj in ['user', 'project', 'task', 'job', 'organization', 'membership', 'invitation']: - response = get_method('admin1', obj, page_size='all') + response = get_method('admin1', f'{obj}s', page_size='all') with open(osp.join(ASSETS_DIR, f'{obj}s.json'), 'w') as f: json.dump(response.json(), f, indent=2, sort_keys=True) + + if obj == 'job': + annotations[obj] = {} + for job in response.json()['results']: + jid = job["id"] + response = get_method('admin1', f'jobs/{jid}/annotations') + annotations[obj][jid] = response.json() + +with open(osp.join(ASSETS_DIR, f'annotations.json'), 'w') as f: + json.dump(annotations, f, indent=2, sort_keys=True)