People: Add subjects API #22
This commit is contained in:
parent
5f07b8bb10
commit
97af133763
16 changed files with 566 additions and 242 deletions
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-04-23 13:30+0000\n"
|
||||
"POT-Creation-Date: 2021-09-02 14:05+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -17,273 +17,277 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: messages.go:74
|
||||
#: messages.go:75
|
||||
msgid "Unexpected error, please try again"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:75
|
||||
#: messages.go:76
|
||||
msgid "Invalid request"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:76
|
||||
#: messages.go:77
|
||||
msgid "Changes could not be saved"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:77
|
||||
#: messages.go:78
|
||||
msgid "Could not be deleted"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:78
|
||||
#: messages.go:79
|
||||
#, c-format
|
||||
msgid "%s already exists"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:79 messages.go:82
|
||||
#: messages.go:80 messages.go:83
|
||||
msgid "Not found on server, deleted?"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:80
|
||||
#: messages.go:81
|
||||
msgid "File not found"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:81
|
||||
#: messages.go:82
|
||||
msgid "Selection not found"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:83
|
||||
#: messages.go:84
|
||||
msgid "Account not found"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:84
|
||||
#: messages.go:85
|
||||
msgid "User not found"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:85
|
||||
#: messages.go:86
|
||||
msgid "Label not found"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:86
|
||||
#: messages.go:87
|
||||
msgid "Album not found"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:87
|
||||
msgid "Not available in public mode"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:88
|
||||
msgid "not available in read-only mode"
|
||||
msgid "Subject not found"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:89
|
||||
msgid "Please log in and try again"
|
||||
msgid "Not available in public mode"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:90
|
||||
msgid "Upload might be offensive"
|
||||
msgid "not available in read-only mode"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:91
|
||||
msgid "No items selected"
|
||||
msgid "Please log in and try again"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:92
|
||||
msgid "Failed creating file, please check permissions"
|
||||
msgid "Upload might be offensive"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:93
|
||||
msgid "Failed creating folder, please check permissions"
|
||||
msgid "No items selected"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:94
|
||||
msgid "Could not connect, please try again"
|
||||
msgid "Failed creating file, please check permissions"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:95
|
||||
msgid "Invalid password, please try again"
|
||||
msgid "Failed creating folder, please check permissions"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:96
|
||||
msgid "Feature disabled"
|
||||
msgid "Could not connect, please try again"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:97
|
||||
msgid "No labels selected"
|
||||
msgid "Invalid password, please try again"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:98
|
||||
msgid "No albums selected"
|
||||
msgid "Feature disabled"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:99
|
||||
msgid "No files available for download"
|
||||
msgid "No labels selected"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:100
|
||||
msgid "Failed to create zip file"
|
||||
msgid "No albums selected"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:101
|
||||
msgid "Invalid credentials"
|
||||
msgid "No files available for download"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:102
|
||||
msgid "Failed to create zip file"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:103
|
||||
msgid "Invalid credentials"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:104
|
||||
msgid "Invalid link"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:105
|
||||
#: messages.go:107
|
||||
msgid "Changes successfully saved"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:106
|
||||
#: messages.go:108
|
||||
msgid "Album created"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:107
|
||||
#: messages.go:109
|
||||
msgid "Album saved"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:108
|
||||
#: messages.go:110
|
||||
#, c-format
|
||||
msgid "Album %s deleted"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:109
|
||||
#: messages.go:111
|
||||
msgid "Album contents cloned"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:110
|
||||
#: messages.go:112
|
||||
msgid "File removed from stack"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:111
|
||||
msgid "File deleted"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:112
|
||||
#, c-format
|
||||
msgid "Selection added to %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:113
|
||||
#, c-format
|
||||
msgid "One entry added to %s"
|
||||
msgid "File deleted"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:114
|
||||
#, c-format
|
||||
msgid "%d entries added to %s"
|
||||
msgid "Selection added to %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:115
|
||||
#, c-format
|
||||
msgid "One entry removed from %s"
|
||||
msgid "One entry added to %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:116
|
||||
#, c-format
|
||||
msgid "%d entries removed from %s"
|
||||
msgid "%d entries added to %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:117
|
||||
msgid "Account created"
|
||||
#, c-format
|
||||
msgid "One entry removed from %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:118
|
||||
msgid "Account saved"
|
||||
#, c-format
|
||||
msgid "%d entries removed from %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:119
|
||||
msgid "Account deleted"
|
||||
msgid "Account created"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:120
|
||||
msgid "Settings saved"
|
||||
msgid "Account saved"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:121
|
||||
msgid "Password changed"
|
||||
msgid "Account deleted"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:122
|
||||
#, c-format
|
||||
msgid "Import completed in %d s"
|
||||
msgid "Settings saved"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:123
|
||||
msgid "Import canceled"
|
||||
msgid "Password changed"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:124
|
||||
#, c-format
|
||||
msgid "Indexing completed in %d s"
|
||||
msgid "Import completed in %d s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:125
|
||||
msgid "Indexing originals..."
|
||||
msgid "Import canceled"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:126
|
||||
#, c-format
|
||||
msgid "Indexing files in %s"
|
||||
msgid "Indexing completed in %d s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:127
|
||||
msgid "Indexing canceled"
|
||||
msgid "Indexing originals..."
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:128
|
||||
#, c-format
|
||||
msgid "Removed %d files and %d photos"
|
||||
msgid "Indexing files in %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:129
|
||||
#, c-format
|
||||
msgid "Moving files from %s"
|
||||
msgid "Indexing canceled"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:130
|
||||
#, c-format
|
||||
msgid "Copying files from %s"
|
||||
msgid "Removed %d files and %d photos"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:131
|
||||
msgid "Labels deleted"
|
||||
#, c-format
|
||||
msgid "Moving files from %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:132
|
||||
msgid "Label saved"
|
||||
#, c-format
|
||||
msgid "Copying files from %s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:133
|
||||
msgid "Labels deleted"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:134
|
||||
msgid "Label saved"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:135
|
||||
#, c-format
|
||||
msgid "%d files uploaded in %d s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:134
|
||||
#: messages.go:136
|
||||
msgid "Selection approved"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:135
|
||||
#: messages.go:137
|
||||
msgid "Selection archived"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:136
|
||||
#: messages.go:138
|
||||
msgid "Selection restored"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:137
|
||||
#: messages.go:139
|
||||
msgid "Selection marked as private"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:138
|
||||
#: messages.go:140
|
||||
msgid "Albums deleted"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:139
|
||||
#: messages.go:141
|
||||
#, c-format
|
||||
msgid "Zip created in %d s"
|
||||
msgstr ""
|
||||
|
||||
#: messages.go:140
|
||||
#: messages.go:142
|
||||
msgid "Permanently deleted"
|
||||
msgstr ""
|
||||
|
|
232
frontend/package-lock.json
generated
232
frontend/package-lock.json
generated
|
@ -1915,13 +1915,13 @@
|
|||
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.6.tgz",
|
||||
"integrity": "sha512-vbwnz7+OhtLO5p5i630fTuQCL+MlUpEMTKHuX+RfetQ+3pFCkItt2JUH+9yMaBG2Hkz6av+T9mwN/acvtIwpbw==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.7.tgz",
|
||||
"integrity": "sha512-OcWy72QNTkcNYtZIb927pRx2cRujrlDWsAx7ejWDnRzwo83gIyF8NeTrMv/7wbnHoeA+Gga9AK4Wo9PlCzhuLg==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@babel/types": "^7.15.0",
|
||||
"@vue/shared": "3.2.6",
|
||||
"@vue/shared": "3.2.7",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
|
@ -1935,27 +1935,27 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.6.tgz",
|
||||
"integrity": "sha512-+a/3oBAzFIXhHt8L5IHJOTP4a5egzvpXYyi13jR7CUYOR1S+Zzv7vBWKYBnKyJLwnrxTZnTQVjeHCgJq743XKg==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.7.tgz",
|
||||
"integrity": "sha512-YZyZNoZlTbTMqyY8QMC8IhwmcDVOiE1DdVwjnXbyihg+XVqpGQkDjNcG5nyMTbtZDKXREsYkcjaZntEfKyWK5g==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.2.6",
|
||||
"@vue/shared": "3.2.6"
|
||||
"@vue/compiler-core": "3.2.7",
|
||||
"@vue/shared": "3.2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.6.tgz",
|
||||
"integrity": "sha512-Ariz1eDsf+2fw6oWXVwnBNtfKHav72RjlWXpEgozYBLnfRPzP+7jhJRw4Nq0OjSsLx2HqjF3QX7HutTjYB0/eA==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.7.tgz",
|
||||
"integrity": "sha512-qjfvRw7/9Q2Qm4cDmrJwTNqnFTXSSI3z/mmS9BSJTYZqh4FC4w+IIYYLWUpS3ef6UTTYY9STC5IUZqfpIod9Uw==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@babel/types": "^7.15.0",
|
||||
"@types/estree": "^0.0.48",
|
||||
"@vue/compiler-core": "3.2.6",
|
||||
"@vue/compiler-dom": "3.2.6",
|
||||
"@vue/compiler-ssr": "3.2.6",
|
||||
"@vue/ref-transform": "3.2.6",
|
||||
"@vue/shared": "3.2.6",
|
||||
"@vue/compiler-core": "3.2.7",
|
||||
"@vue/compiler-dom": "3.2.7",
|
||||
"@vue/compiler-ssr": "3.2.7",
|
||||
"@vue/ref-transform": "3.2.7",
|
||||
"@vue/shared": "3.2.7",
|
||||
"consolidate": "^0.16.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"hash-sum": "^2.0.0",
|
||||
|
@ -1977,12 +1977,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.6.tgz",
|
||||
"integrity": "sha512-A7IKRKHSyPnTC4w1FxHkjzoyjXInsXkcs/oX22nBQ+6AWlXj2Tt1le96CWPOXy5vYlsTYkF1IgfBaKIdeN/39g==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.7.tgz",
|
||||
"integrity": "sha512-4moQTeMujIk+fG8NaMxU5aPhMCnWE+O3xNEK6+kd9GjNoN+n3y3YZ6CkVy+aOP2HpqWenZbS/20TBzOSdon5Cw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.2.6",
|
||||
"@vue/shared": "3.2.6"
|
||||
"@vue/compiler-dom": "3.2.7",
|
||||
"@vue/shared": "3.2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/component-compiler-utils": {
|
||||
|
@ -2082,21 +2082,21 @@
|
|||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||
},
|
||||
"node_modules/@vue/ref-transform": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.6.tgz",
|
||||
"integrity": "sha512-ie39+Y4nbirDLvH+WEq6Eo/l3n3mFATayqR+kEMSphrtMW6Uh/eEMx1Gk2Jnf82zmj3VLRq7dnmPx72JLcBYkQ==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.7.tgz",
|
||||
"integrity": "sha512-5I7IeUqoDEhPmkPHBhw7YlsFCFO/ZXHWwgdrokQATyVRkEkqeAd8erthuZ9a4sZAo5JBYmxjYw8WD9Kx9mabmg==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@vue/compiler-core": "3.2.6",
|
||||
"@vue/shared": "3.2.6",
|
||||
"@vue/compiler-core": "3.2.7",
|
||||
"@vue/shared": "3.2.7",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.25.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.6.tgz",
|
||||
"integrity": "sha512-uwX0Qs2e6kdF+WmxwuxJxOnKs/wEkMArtYpHSm7W+VY/23Tl8syMRyjnzEeXrNCAP0/8HZxEGkHJsjPEDNRuHw=="
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.7.tgz",
|
||||
"integrity": "sha512-YwGOcNZjOY/MmadpzFBXWyHEwZSf0lVU4XF5zpD7tXC9dmqjdo38Jkk06wATu4LYHDPW4emXKMB5YLFPWPkwFA=="
|
||||
},
|
||||
"node_modules/@vvo/tzdb": {
|
||||
"version": "6.10.0",
|
||||
|
@ -3846,9 +3846,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.16.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.4.tgz",
|
||||
"integrity": "sha512-Tq4GVE6XCjE+hcyW6hPy0ofN3hwtLudz5ZRdrlCnsnD/xkm/PWQRudzYHiKgZKUcefV6Q57fhDHjZHJP5dpfSg==",
|
||||
"version": "3.17.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.17.1.tgz",
|
||||
"integrity": "sha512-C8i/FNpVN2Ti89QIJcFn9ZQmnM+HaAQr2OpE+ja3TRM9Q34FigsGlAVuwPGkIgydSVClo/1l1D1grP8LVt9IYA==",
|
||||
"hasInstallScript": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
|
@ -3856,9 +3856,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.16.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.16.4.tgz",
|
||||
"integrity": "sha512-IzCSomxRdahCYb6G3HiN6pl3JCiM0NMunRcNa1pIeC7g17Vd6Ue3AT9anQiENPIm/svThUVer1pIbLMDERIsFw==",
|
||||
"version": "3.17.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.17.1.tgz",
|
||||
"integrity": "sha512-Oqp6qybMdCFcWSroh/6Q8j7YNOjRD0ThY02cAd6rugr//FCkMYonizLV8AryLU5wNJOweauIBxQYCZoV3emfcw==",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.16.8",
|
||||
"semver": "7.0.0"
|
||||
|
@ -4759,9 +4759,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.3.826",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.826.tgz",
|
||||
"integrity": "sha512-bpLc4QU4B8PYmdO4MSu2ZBTMD8lAaEXRS43C09lB31BvYwuk9UxgBRXbY5OJBw7VuMGcg2MZG5FyTaP9u4PQnw=="
|
||||
"version": "1.3.827",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.827.tgz",
|
||||
"integrity": "sha512-ye+4uQOY/jbjRutMcE/EmOcNwUeo1qo9aKL2tPyb09cU3lmxNeyDF4RWiemmkknW+p29h7dyDqy02higTxc9/A=="
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
|
@ -6539,19 +6539,19 @@
|
|||
"deprecated": "flatten is deprecated in favor of utility frameworks such as lodash."
|
||||
},
|
||||
"node_modules/flow-parser": {
|
||||
"version": "0.158.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.158.0.tgz",
|
||||
"integrity": "sha512-0hMsPkBTRrkII/0YiG9ehOxFXy4gOWdk8RSRze5WbfeKAQpL5kC2K4BmumyTfU9o5gr7/llgElF3UpSSrjzQAA==",
|
||||
"version": "0.159.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.159.0.tgz",
|
||||
"integrity": "sha512-/AFSLMSbqictmgPm+vrXBD0rLTsVRrlKfiGRoDjt/WhhUxqy5ZMuLVHbRD/g3C3JRnJgDrKSb3+piQoM1dzVGw==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/flow-remove-types": {
|
||||
"version": "2.158.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.158.0.tgz",
|
||||
"integrity": "sha512-mLDU+B2LuiCg0KA9V0A5OdgI5evugWlHKqG+GLlNIrtOPEPO497p3PJAUxGD3SR+gJmtxCDdgL+qLZnw5op9bA==",
|
||||
"version": "2.159.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.159.0.tgz",
|
||||
"integrity": "sha512-1S1qkw8HTYW2ypoqnTQyGHQEWh6kxKc7SUdj07lOa9WzEuhdu2+wr+SO5BBxCwoqJ4XrwBgegmWnEFrAz2WF/w==",
|
||||
"dependencies": {
|
||||
"flow-parser": "^0.158.0",
|
||||
"flow-parser": "^0.159.0",
|
||||
"pirates": "^3.0.2",
|
||||
"vlq": "^0.2.1"
|
||||
},
|
||||
|
@ -8844,9 +8844,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/mini-css-extract-plugin": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.2.1.tgz",
|
||||
"integrity": "sha512-A0GBXpz8WIPgh2HfASJ0EeY8grd2dGxmC4R8uTujFJXZY7zFy0nvYSYW6SKCLKlz7y45BdHONfaxZQMIZpeF/w==",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.2.2.tgz",
|
||||
"integrity": "sha512-eUjQ/q1rQIeHWgIx7ny/DNgXHcMXHdBwgrZQK7Ev8dbR+HxhroFM2Cb6kMiswOYaq05IRJhPuQqXWUABIjjA3g==",
|
||||
"dependencies": {
|
||||
"schema-utils": "^3.1.0"
|
||||
},
|
||||
|
@ -13015,9 +13015,9 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.38.2",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.38.2.tgz",
|
||||
"integrity": "sha512-Bz1fG6qiyF0FX6m/I+VxtdVKz1Dfmg/e9kfDy2PhWOkq3T384q2KxwIfP0fXpeI+EyyETdOauH+cRHQDFASllA==",
|
||||
"version": "1.39.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.39.0.tgz",
|
||||
"integrity": "sha512-F4o+RhJkNOIG0b6QudYU8c78ZADKZjKDk5cyrf8XTKWfrgbtyVVXImFstJrc+1pkQDCggyidIOytq6gS4gCCZg==",
|
||||
"dependencies": {
|
||||
"chokidar": ">=3.0.0 <4.0.0"
|
||||
},
|
||||
|
@ -14354,9 +14354,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/terser-webpack-plugin": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.0.tgz",
|
||||
"integrity": "sha512-FpR4Qe0Yt4knSQ5u2bA1wkM0R8VlVsvhyfSHvomXRivS4vPLk0dJV2IhRBIHRABh7AFutdMeElIA5y1dETwMBg==",
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.1.tgz",
|
||||
"integrity": "sha512-mUAWsS2RDNL3rEr0ZTr7hm/R1DDxNwrED7Kf59F2rgFTfy+LrnciwA51MNWhGGQcqHnqvbPHgkW9LYr5HGBhfw==",
|
||||
"dependencies": {
|
||||
"jest-worker": "^27.0.6",
|
||||
"p-limit": "^3.1.0",
|
||||
|
@ -15329,9 +15329,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.51.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.51.1.tgz",
|
||||
"integrity": "sha512-xsn3lwqEKoFvqn4JQggPSRxE4dhsRcysWTqYABAZlmavcoTmwlOb9b1N36Inbt/eIispSkuHa80/FJkDTPos1A==",
|
||||
"version": "5.51.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.51.2.tgz",
|
||||
"integrity": "sha512-odydxP4WA3XYYzwSQUivPxywdzMlY42bbfxMwCaEtHb+i/N9uzKSHcLgWkXo/Gsa+4Zlzf3Jg0hEHn1FnZpk2Q==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.0",
|
||||
"@types/estree": "^0.0.50",
|
||||
|
@ -17217,13 +17217,13 @@
|
|||
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
|
||||
},
|
||||
"@vue/compiler-core": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.6.tgz",
|
||||
"integrity": "sha512-vbwnz7+OhtLO5p5i630fTuQCL+MlUpEMTKHuX+RfetQ+3pFCkItt2JUH+9yMaBG2Hkz6av+T9mwN/acvtIwpbw==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.7.tgz",
|
||||
"integrity": "sha512-OcWy72QNTkcNYtZIb927pRx2cRujrlDWsAx7ejWDnRzwo83gIyF8NeTrMv/7wbnHoeA+Gga9AK4Wo9PlCzhuLg==",
|
||||
"requires": {
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@babel/types": "^7.15.0",
|
||||
"@vue/shared": "3.2.6",
|
||||
"@vue/shared": "3.2.7",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
|
@ -17236,27 +17236,27 @@
|
|||
}
|
||||
},
|
||||
"@vue/compiler-dom": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.6.tgz",
|
||||
"integrity": "sha512-+a/3oBAzFIXhHt8L5IHJOTP4a5egzvpXYyi13jR7CUYOR1S+Zzv7vBWKYBnKyJLwnrxTZnTQVjeHCgJq743XKg==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.7.tgz",
|
||||
"integrity": "sha512-YZyZNoZlTbTMqyY8QMC8IhwmcDVOiE1DdVwjnXbyihg+XVqpGQkDjNcG5nyMTbtZDKXREsYkcjaZntEfKyWK5g==",
|
||||
"requires": {
|
||||
"@vue/compiler-core": "3.2.6",
|
||||
"@vue/shared": "3.2.6"
|
||||
"@vue/compiler-core": "3.2.7",
|
||||
"@vue/shared": "3.2.7"
|
||||
}
|
||||
},
|
||||
"@vue/compiler-sfc": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.6.tgz",
|
||||
"integrity": "sha512-Ariz1eDsf+2fw6oWXVwnBNtfKHav72RjlWXpEgozYBLnfRPzP+7jhJRw4Nq0OjSsLx2HqjF3QX7HutTjYB0/eA==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.7.tgz",
|
||||
"integrity": "sha512-qjfvRw7/9Q2Qm4cDmrJwTNqnFTXSSI3z/mmS9BSJTYZqh4FC4w+IIYYLWUpS3ef6UTTYY9STC5IUZqfpIod9Uw==",
|
||||
"requires": {
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@babel/types": "^7.15.0",
|
||||
"@types/estree": "^0.0.48",
|
||||
"@vue/compiler-core": "3.2.6",
|
||||
"@vue/compiler-dom": "3.2.6",
|
||||
"@vue/compiler-ssr": "3.2.6",
|
||||
"@vue/ref-transform": "3.2.6",
|
||||
"@vue/shared": "3.2.6",
|
||||
"@vue/compiler-core": "3.2.7",
|
||||
"@vue/compiler-dom": "3.2.7",
|
||||
"@vue/compiler-ssr": "3.2.7",
|
||||
"@vue/ref-transform": "3.2.7",
|
||||
"@vue/shared": "3.2.7",
|
||||
"consolidate": "^0.16.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"hash-sum": "^2.0.0",
|
||||
|
@ -17277,12 +17277,12 @@
|
|||
}
|
||||
},
|
||||
"@vue/compiler-ssr": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.6.tgz",
|
||||
"integrity": "sha512-A7IKRKHSyPnTC4w1FxHkjzoyjXInsXkcs/oX22nBQ+6AWlXj2Tt1le96CWPOXy5vYlsTYkF1IgfBaKIdeN/39g==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.7.tgz",
|
||||
"integrity": "sha512-4moQTeMujIk+fG8NaMxU5aPhMCnWE+O3xNEK6+kd9GjNoN+n3y3YZ6CkVy+aOP2HpqWenZbS/20TBzOSdon5Cw==",
|
||||
"requires": {
|
||||
"@vue/compiler-dom": "3.2.6",
|
||||
"@vue/shared": "3.2.6"
|
||||
"@vue/compiler-dom": "3.2.7",
|
||||
"@vue/shared": "3.2.7"
|
||||
}
|
||||
},
|
||||
"@vue/component-compiler-utils": {
|
||||
|
@ -17360,21 +17360,21 @@
|
|||
}
|
||||
},
|
||||
"@vue/ref-transform": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.6.tgz",
|
||||
"integrity": "sha512-ie39+Y4nbirDLvH+WEq6Eo/l3n3mFATayqR+kEMSphrtMW6Uh/eEMx1Gk2Jnf82zmj3VLRq7dnmPx72JLcBYkQ==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.7.tgz",
|
||||
"integrity": "sha512-5I7IeUqoDEhPmkPHBhw7YlsFCFO/ZXHWwgdrokQATyVRkEkqeAd8erthuZ9a4sZAo5JBYmxjYw8WD9Kx9mabmg==",
|
||||
"requires": {
|
||||
"@babel/parser": "^7.15.0",
|
||||
"@vue/compiler-core": "3.2.6",
|
||||
"@vue/shared": "3.2.6",
|
||||
"@vue/compiler-core": "3.2.7",
|
||||
"@vue/shared": "3.2.7",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.25.7"
|
||||
}
|
||||
},
|
||||
"@vue/shared": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.6.tgz",
|
||||
"integrity": "sha512-uwX0Qs2e6kdF+WmxwuxJxOnKs/wEkMArtYpHSm7W+VY/23Tl8syMRyjnzEeXrNCAP0/8HZxEGkHJsjPEDNRuHw=="
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.7.tgz",
|
||||
"integrity": "sha512-YwGOcNZjOY/MmadpzFBXWyHEwZSf0lVU4XF5zpD7tXC9dmqjdo38Jkk06wATu4LYHDPW4emXKMB5YLFPWPkwFA=="
|
||||
},
|
||||
"@vvo/tzdb": {
|
||||
"version": "6.10.0",
|
||||
|
@ -18748,14 +18748,14 @@
|
|||
"optional": true
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.16.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.4.tgz",
|
||||
"integrity": "sha512-Tq4GVE6XCjE+hcyW6hPy0ofN3hwtLudz5ZRdrlCnsnD/xkm/PWQRudzYHiKgZKUcefV6Q57fhDHjZHJP5dpfSg=="
|
||||
"version": "3.17.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.17.1.tgz",
|
||||
"integrity": "sha512-C8i/FNpVN2Ti89QIJcFn9ZQmnM+HaAQr2OpE+ja3TRM9Q34FigsGlAVuwPGkIgydSVClo/1l1D1grP8LVt9IYA=="
|
||||
},
|
||||
"core-js-compat": {
|
||||
"version": "3.16.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.16.4.tgz",
|
||||
"integrity": "sha512-IzCSomxRdahCYb6G3HiN6pl3JCiM0NMunRcNa1pIeC7g17Vd6Ue3AT9anQiENPIm/svThUVer1pIbLMDERIsFw==",
|
||||
"version": "3.17.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.17.1.tgz",
|
||||
"integrity": "sha512-Oqp6qybMdCFcWSroh/6Q8j7YNOjRD0ThY02cAd6rugr//FCkMYonizLV8AryLU5wNJOweauIBxQYCZoV3emfcw==",
|
||||
"requires": {
|
||||
"browserslist": "^4.16.8",
|
||||
"semver": "7.0.0"
|
||||
|
@ -19398,9 +19398,9 @@
|
|||
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.826",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.826.tgz",
|
||||
"integrity": "sha512-bpLc4QU4B8PYmdO4MSu2ZBTMD8lAaEXRS43C09lB31BvYwuk9UxgBRXbY5OJBw7VuMGcg2MZG5FyTaP9u4PQnw=="
|
||||
"version": "1.3.827",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.827.tgz",
|
||||
"integrity": "sha512-ye+4uQOY/jbjRutMcE/EmOcNwUeo1qo9aKL2tPyb09cU3lmxNeyDF4RWiemmkknW+p29h7dyDqy02higTxc9/A=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
|
@ -20767,16 +20767,16 @@
|
|||
"integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg=="
|
||||
},
|
||||
"flow-parser": {
|
||||
"version": "0.158.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.158.0.tgz",
|
||||
"integrity": "sha512-0hMsPkBTRrkII/0YiG9ehOxFXy4gOWdk8RSRze5WbfeKAQpL5kC2K4BmumyTfU9o5gr7/llgElF3UpSSrjzQAA=="
|
||||
"version": "0.159.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.159.0.tgz",
|
||||
"integrity": "sha512-/AFSLMSbqictmgPm+vrXBD0rLTsVRrlKfiGRoDjt/WhhUxqy5ZMuLVHbRD/g3C3JRnJgDrKSb3+piQoM1dzVGw=="
|
||||
},
|
||||
"flow-remove-types": {
|
||||
"version": "2.158.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.158.0.tgz",
|
||||
"integrity": "sha512-mLDU+B2LuiCg0KA9V0A5OdgI5evugWlHKqG+GLlNIrtOPEPO497p3PJAUxGD3SR+gJmtxCDdgL+qLZnw5op9bA==",
|
||||
"version": "2.159.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.159.0.tgz",
|
||||
"integrity": "sha512-1S1qkw8HTYW2ypoqnTQyGHQEWh6kxKc7SUdj07lOa9WzEuhdu2+wr+SO5BBxCwoqJ4XrwBgegmWnEFrAz2WF/w==",
|
||||
"requires": {
|
||||
"flow-parser": "^0.158.0",
|
||||
"flow-parser": "^0.159.0",
|
||||
"pirates": "^3.0.2",
|
||||
"vlq": "^0.2.1"
|
||||
},
|
||||
|
@ -22489,9 +22489,9 @@
|
|||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
|
||||
},
|
||||
"mini-css-extract-plugin": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.2.1.tgz",
|
||||
"integrity": "sha512-A0GBXpz8WIPgh2HfASJ0EeY8grd2dGxmC4R8uTujFJXZY7zFy0nvYSYW6SKCLKlz7y45BdHONfaxZQMIZpeF/w==",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.2.2.tgz",
|
||||
"integrity": "sha512-eUjQ/q1rQIeHWgIx7ny/DNgXHcMXHdBwgrZQK7Ev8dbR+HxhroFM2Cb6kMiswOYaq05IRJhPuQqXWUABIjjA3g==",
|
||||
"requires": {
|
||||
"schema-utils": "^3.1.0"
|
||||
},
|
||||
|
@ -25525,9 +25525,9 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.38.2",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.38.2.tgz",
|
||||
"integrity": "sha512-Bz1fG6qiyF0FX6m/I+VxtdVKz1Dfmg/e9kfDy2PhWOkq3T384q2KxwIfP0fXpeI+EyyETdOauH+cRHQDFASllA==",
|
||||
"version": "1.39.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.39.0.tgz",
|
||||
"integrity": "sha512-F4o+RhJkNOIG0b6QudYU8c78ZADKZjKDk5cyrf8XTKWfrgbtyVVXImFstJrc+1pkQDCggyidIOytq6gS4gCCZg==",
|
||||
"requires": {
|
||||
"chokidar": ">=3.0.0 <4.0.0"
|
||||
}
|
||||
|
@ -26619,9 +26619,9 @@
|
|||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.0.tgz",
|
||||
"integrity": "sha512-FpR4Qe0Yt4knSQ5u2bA1wkM0R8VlVsvhyfSHvomXRivS4vPLk0dJV2IhRBIHRABh7AFutdMeElIA5y1dETwMBg==",
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.1.tgz",
|
||||
"integrity": "sha512-mUAWsS2RDNL3rEr0ZTr7hm/R1DDxNwrED7Kf59F2rgFTfy+LrnciwA51MNWhGGQcqHnqvbPHgkW9LYr5HGBhfw==",
|
||||
"requires": {
|
||||
"jest-worker": "^27.0.6",
|
||||
"p-limit": "^3.1.0",
|
||||
|
@ -27333,9 +27333,9 @@
|
|||
}
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.51.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.51.1.tgz",
|
||||
"integrity": "sha512-xsn3lwqEKoFvqn4JQggPSRxE4dhsRcysWTqYABAZlmavcoTmwlOb9b1N36Inbt/eIispSkuHa80/FJkDTPos1A==",
|
||||
"version": "5.51.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.51.2.tgz",
|
||||
"integrity": "sha512-odydxP4WA3XYYzwSQUivPxywdzMlY42bbfxMwCaEtHb+i/N9uzKSHcLgWkXo/Gsa+4Zlzf3Jg0hEHn1FnZpk2Q==",
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.0",
|
||||
"@types/estree": "^0.0.50",
|
||||
|
|
|
@ -39,17 +39,18 @@ export class Subject extends RestModel {
|
|||
return {
|
||||
UID: "",
|
||||
Thumb: "",
|
||||
PreviewSrc: "",
|
||||
ThumbSrc: "",
|
||||
Type: "",
|
||||
Src: "",
|
||||
Slug: "",
|
||||
Name: "",
|
||||
Alias: "",
|
||||
Bio: "",
|
||||
Notes: "",
|
||||
Favorite: false,
|
||||
Private: false,
|
||||
Excluded: false,
|
||||
FileCount: 0,
|
||||
Files: 0,
|
||||
Metadata: {},
|
||||
CreatedAt: "",
|
||||
UpdatedAt: "",
|
||||
|
@ -113,7 +114,7 @@ export class Subject extends RestModel {
|
|||
}
|
||||
|
||||
static batchSize() {
|
||||
return 24;
|
||||
return 60;
|
||||
}
|
||||
|
||||
static getCollectionResource() {
|
||||
|
|
|
@ -11,6 +11,9 @@ var Permissions = ACL{
|
|||
ResourceConfigOptions: Roles{
|
||||
RoleAdmin: Actions{ActionDefault: true},
|
||||
},
|
||||
ResourceSubjects: Roles{
|
||||
RoleAdmin: Actions{ActionDefault: true},
|
||||
},
|
||||
ResourceAlbums: Roles{
|
||||
RoleAdmin: Actions{ActionDefault: true},
|
||||
RoleGuest: Actions{ActionSearch: true, ActionRead: true},
|
||||
|
|
|
@ -9,6 +9,7 @@ const (
|
|||
ResourceSettings Resource = "settings"
|
||||
ResourceLogs Resource = "logs"
|
||||
ResourceAccounts Resource = "accounts"
|
||||
ResourceSubjects Resource = "subjects"
|
||||
ResourceAlbums Resource = "albums"
|
||||
ResourceCameras Resource = "cameras"
|
||||
ResourceCategories Resource = "categories"
|
||||
|
|
73
internal/api/subject.go
Normal file
73
internal/api/subject.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/internal/i18n"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
// GetSubjects finds and returns subjects as JSON.
|
||||
//
|
||||
// GET /api/v1/subjects
|
||||
func GetSubjects(router *gin.RouterGroup) {
|
||||
router.GET("/subjects", func(c *gin.Context) {
|
||||
s := Auth(SessionID(c), acl.ResourceSubjects, acl.ActionSearch)
|
||||
|
||||
if s.Invalid() {
|
||||
AbortUnauthorized(c)
|
||||
return
|
||||
}
|
||||
|
||||
var f form.SubjectSearch
|
||||
|
||||
err := c.MustBindWith(&f, binding.Form)
|
||||
|
||||
if err != nil {
|
||||
AbortBadRequest(c)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := query.SubjectSearch(f)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(400, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
AddCountHeader(c, len(result))
|
||||
AddLimitHeader(c, f.Count)
|
||||
AddOffsetHeader(c, f.Offset)
|
||||
AddTokenHeaders(c)
|
||||
|
||||
c.JSON(http.StatusOK, result)
|
||||
})
|
||||
}
|
||||
|
||||
// GetSubject returns a subject as JSON.
|
||||
//
|
||||
// GET /api/v1/subjects/:uid
|
||||
func GetSubject(router *gin.RouterGroup) {
|
||||
router.GET("/subjects/:uid", func(c *gin.Context) {
|
||||
s := Auth(SessionID(c), acl.ResourceSubjects, acl.ActionRead)
|
||||
|
||||
if s.Invalid() {
|
||||
AbortUnauthorized(c)
|
||||
return
|
||||
}
|
||||
|
||||
if subj := entity.FindSubject(c.Param("uid")); subj == nil {
|
||||
Abort(c, http.StatusNotFound, i18n.ErrSubjectNotFound)
|
||||
return
|
||||
} else {
|
||||
c.JSON(http.StatusOK, subj)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
46
internal/api/subject_test.go
Normal file
46
internal/api/subject_test.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetSubjects(t *testing.T) {
|
||||
t.Run("successful request", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
GetSubjects(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/subjects?count=10")
|
||||
count := gjson.Get(r.Body.String(), "#")
|
||||
assert.LessOrEqual(t, int64(3), count.Int())
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("invalid request", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
GetSubjects(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/subjects?xxx=10")
|
||||
assert.Equal(t, http.StatusBadRequest, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetSubject(t *testing.T) {
|
||||
t.Run("successful request", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
GetSubject(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/subjects/jqy1y111h1njaaaa")
|
||||
val := gjson.Get(r.Body.String(), "Slug")
|
||||
assert.Equal(t, "dangling-subject", val.String())
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("invalid request", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
GetSubject(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/subjects/xxx1y111h1njaaaa")
|
||||
val := gjson.Get(r.Body.String(), "error")
|
||||
assert.Equal(t, "Subject not found", val.String())
|
||||
assert.Equal(t, http.StatusNotFound, r.Code)
|
||||
})
|
||||
}
|
|
@ -4,6 +4,9 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/pkg/colors"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
|
@ -12,52 +15,52 @@ import (
|
|||
|
||||
// ClientConfig represents HTTP client / Web UI config options.
|
||||
type ClientConfig struct {
|
||||
Mode string `json:"mode"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Copyright string `json:"copyright"`
|
||||
Flags string `json:"flags"`
|
||||
BaseUri string `json:"baseUri"`
|
||||
StaticUri string `json:"staticUri"`
|
||||
ApiUri string `json:"apiUri"`
|
||||
ContentUri string `json:"contentUri"`
|
||||
SiteUrl string `json:"siteUrl"`
|
||||
SitePreview string `json:"sitePreview"`
|
||||
SiteTitle string `json:"siteTitle"`
|
||||
SiteCaption string `json:"siteCaption"`
|
||||
SiteDescription string `json:"siteDescription"`
|
||||
SiteAuthor string `json:"siteAuthor"`
|
||||
Debug bool `json:"debug"`
|
||||
Test bool `json:"test"`
|
||||
Demo bool `json:"demo"`
|
||||
Sponsor bool `json:"sponsor"`
|
||||
ReadOnly bool `json:"readonly"`
|
||||
UploadNSFW bool `json:"uploadNSFW"`
|
||||
Public bool `json:"public"`
|
||||
Experimental bool `json:"experimental"`
|
||||
AlbumCategories []string `json:"albumCategories"`
|
||||
Albums entity.Albums `json:"albums"`
|
||||
Cameras entity.Cameras `json:"cameras"`
|
||||
Lenses entity.Lenses `json:"lenses"`
|
||||
Countries entity.Countries `json:"countries"`
|
||||
Subjects entity.Subjects `json:"subjects"`
|
||||
Thumbs ThumbTypes `json:"thumbs"`
|
||||
Status string `json:"status"`
|
||||
MapKey string `json:"mapKey"`
|
||||
DownloadToken string `json:"downloadToken"`
|
||||
PreviewToken string `json:"previewToken"`
|
||||
JSHash string `json:"jsHash"`
|
||||
CSSHash string `json:"cssHash"`
|
||||
ManifestHash string `json:"manifestHash"`
|
||||
Settings Settings `json:"settings"`
|
||||
Disable ClientDisable `json:"disable"`
|
||||
Count ClientCounts `json:"count"`
|
||||
Pos ClientPosition `json:"pos"`
|
||||
Years Years `json:"years"`
|
||||
Colors []map[string]string `json:"colors"`
|
||||
Categories CategoryLabels `json:"categories"`
|
||||
Clip int `json:"clip"`
|
||||
Server RuntimeInfo `json:"server"`
|
||||
Mode string `json:"mode"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Copyright string `json:"copyright"`
|
||||
Flags string `json:"flags"`
|
||||
BaseUri string `json:"baseUri"`
|
||||
StaticUri string `json:"staticUri"`
|
||||
ApiUri string `json:"apiUri"`
|
||||
ContentUri string `json:"contentUri"`
|
||||
SiteUrl string `json:"siteUrl"`
|
||||
SitePreview string `json:"sitePreview"`
|
||||
SiteTitle string `json:"siteTitle"`
|
||||
SiteCaption string `json:"siteCaption"`
|
||||
SiteDescription string `json:"siteDescription"`
|
||||
SiteAuthor string `json:"siteAuthor"`
|
||||
Debug bool `json:"debug"`
|
||||
Test bool `json:"test"`
|
||||
Demo bool `json:"demo"`
|
||||
Sponsor bool `json:"sponsor"`
|
||||
ReadOnly bool `json:"readonly"`
|
||||
UploadNSFW bool `json:"uploadNSFW"`
|
||||
Public bool `json:"public"`
|
||||
Experimental bool `json:"experimental"`
|
||||
AlbumCategories []string `json:"albumCategories"`
|
||||
Albums entity.Albums `json:"albums"`
|
||||
Cameras entity.Cameras `json:"cameras"`
|
||||
Lenses entity.Lenses `json:"lenses"`
|
||||
Countries entity.Countries `json:"countries"`
|
||||
Subjects query.SubjectResults `json:"subjects"`
|
||||
Thumbs ThumbTypes `json:"thumbs"`
|
||||
Status string `json:"status"`
|
||||
MapKey string `json:"mapKey"`
|
||||
DownloadToken string `json:"downloadToken"`
|
||||
PreviewToken string `json:"previewToken"`
|
||||
JSHash string `json:"jsHash"`
|
||||
CSSHash string `json:"cssHash"`
|
||||
ManifestHash string `json:"manifestHash"`
|
||||
Settings Settings `json:"settings"`
|
||||
Disable ClientDisable `json:"disable"`
|
||||
Count ClientCounts `json:"count"`
|
||||
Pos ClientPosition `json:"pos"`
|
||||
Years Years `json:"years"`
|
||||
Colors []map[string]string `json:"colors"`
|
||||
Categories CategoryLabels `json:"categories"`
|
||||
Clip int `json:"clip"`
|
||||
Server RuntimeInfo `json:"server"`
|
||||
}
|
||||
|
||||
// Years represents a list of years.
|
||||
|
@ -399,6 +402,8 @@ func (c *Config) UserConfig() ClientConfig {
|
|||
Order("country_slug").
|
||||
Find(&result.Countries)
|
||||
|
||||
result.Subjects, _ = query.SubjectSearch(form.SubjectSearch{Type: entity.SubjectPerson})
|
||||
|
||||
c.Db().
|
||||
Where("id IN (SELECT photos.camera_id FROM photos WHERE photos.photo_quality >= 0 OR photos.deleted_at IS NULL)").
|
||||
Where("deleted_at IS NULL").
|
||||
|
|
|
@ -37,7 +37,7 @@ type Subject struct {
|
|||
Favorite bool `gorm:"default:false" json:"Favorite" yaml:"Favorite,omitempty"`
|
||||
Private bool `gorm:"default:false" json:"Private" yaml:"Private,omitempty"`
|
||||
Excluded bool `gorm:"default:false" json:"Excluded" yaml:"Excluded,omitempty"`
|
||||
FileCount int `gorm:"default:0" json:"FileCount" yaml:"-"`
|
||||
FileCount int `gorm:"default:0" json:"Files" yaml:"-"`
|
||||
MetadataJSON json.RawMessage `gorm:"type:MEDIUMBLOB;" json:"Metadata,omitempty" yaml:"Metadata,omitempty"`
|
||||
CreatedAt time.Time `json:"CreatedAt" yaml:"-"`
|
||||
UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"`
|
||||
|
|
|
@ -57,6 +57,7 @@ var SubjectFixtures = SubjectMap{
|
|||
SubjectUID: "jqy1y111h1njaaaa",
|
||||
SubjectSlug: "dangling-subject",
|
||||
SubjectName: "Dangling Subject",
|
||||
SubjectAlias: "Powell",
|
||||
SubjectType: SubjectPerson,
|
||||
SubjectSrc: SrcMarker,
|
||||
Favorite: false,
|
||||
|
|
32
internal/form/subject_search.go
Normal file
32
internal/form/subject_search.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package form
|
||||
|
||||
// SubjectSearch represents search form fields for "/api/v1/subjects".
|
||||
type SubjectSearch struct {
|
||||
Query string `form:"q"`
|
||||
ID string `form:"id"`
|
||||
Type string `form:"type"`
|
||||
Name string `form:"name"`
|
||||
Hidden bool `form:"hidden"`
|
||||
Favorite bool `form:"favorite"`
|
||||
Private bool `form:"private"`
|
||||
Excluded bool `form:"excluded"`
|
||||
Count int `form:"count" binding:"required" serialize:"-"`
|
||||
Offset int `form:"offset" serialize:"-"`
|
||||
Order string `form:"order" serialize:"-"`
|
||||
}
|
||||
|
||||
func (f *SubjectSearch) GetQuery() string {
|
||||
return f.Query
|
||||
}
|
||||
|
||||
func (f *SubjectSearch) SetQuery(q string) {
|
||||
f.Query = q
|
||||
}
|
||||
|
||||
func (f *SubjectSearch) ParseQueryString() error {
|
||||
return ParseQueryString(f)
|
||||
}
|
||||
|
||||
func NewSubjectSearch(query string) SubjectSearch {
|
||||
return SubjectSearch{Query: query}
|
||||
}
|
36
internal/form/subject_search_test.go
Normal file
36
internal/form/subject_search_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package form
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSubjectSearchForm(t *testing.T) {
|
||||
form := &SubjectSearch{}
|
||||
|
||||
assert.IsType(t, new(SubjectSearch), form)
|
||||
}
|
||||
|
||||
func TestParseQueryStringSubject(t *testing.T) {
|
||||
t.Run("Ok", func(t *testing.T) {
|
||||
form := &SubjectSearch{Query: "type:person favorite:true count:5"}
|
||||
|
||||
err := form.ParseQueryString()
|
||||
|
||||
// log.Debugf("%+v\n", form)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("err should be nil")
|
||||
}
|
||||
|
||||
assert.Equal(t, "person", form.Type)
|
||||
assert.Equal(t, true, form.Favorite)
|
||||
assert.Equal(t, 5, form.Count)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSubjectSearch(t *testing.T) {
|
||||
r := NewSubjectSearch("john")
|
||||
assert.IsType(t, SubjectSearch{}, r)
|
||||
}
|
|
@ -14,6 +14,7 @@ const (
|
|||
ErrUserNotFound
|
||||
ErrLabelNotFound
|
||||
ErrAlbumNotFound
|
||||
ErrSubjectNotFound
|
||||
ErrPublic
|
||||
ErrReadOnly
|
||||
ErrUnauthorized
|
||||
|
@ -84,6 +85,7 @@ var Messages = MessageMap{
|
|||
ErrUserNotFound: gettext("User not found"),
|
||||
ErrLabelNotFound: gettext("Label not found"),
|
||||
ErrAlbumNotFound: gettext("Album not found"),
|
||||
ErrSubjectNotFound: gettext("Subject not found"),
|
||||
ErrPublic: gettext("Not available in public mode"),
|
||||
ErrReadOnly: gettext("not available in read-only mode"),
|
||||
ErrUnauthorized: gettext("Please log in and try again"),
|
||||
|
|
97
internal/query/subject_search.go
Normal file
97
internal/query/subject_search.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/pkg/capture"
|
||||
)
|
||||
|
||||
// SubjectResult represents a subject search result.
|
||||
type SubjectResult struct {
|
||||
SubjectUID string `json:"UID"`
|
||||
SubjectType string `json:"Type"`
|
||||
SubjectSlug string `json:"Slug"`
|
||||
SubjectName string `json:"Name"`
|
||||
SubjectAlias string `json:"Alias,omitempty"`
|
||||
Thumb string `json:"Thumb,omitempty"`
|
||||
Favorite bool `json:"Favorite,omitempty"`
|
||||
Private bool `json:"Private,omitempty"`
|
||||
Excluded bool `json:"Excluded,omitempty"`
|
||||
FileCount int `json:"Files,omitempty"`
|
||||
}
|
||||
|
||||
// SubjectResults represents subject search results.
|
||||
type SubjectResults []SubjectResult
|
||||
|
||||
// SubjectSearch searches subjects and returns them.
|
||||
func SubjectSearch(f form.SubjectSearch) (results SubjectResults, err error) {
|
||||
if err := f.ParseQueryString(); err != nil {
|
||||
return results, err
|
||||
}
|
||||
|
||||
defer log.Debug(capture.Time(time.Now(), fmt.Sprintf("subjects: search %s", form.Serialize(f, true))))
|
||||
|
||||
// Base query.
|
||||
s := UnscopedDb().Table(entity.Subject{}.TableName()).
|
||||
Select("subject_uid, subject_slug, subject_name, subject_alias, subject_type, thumb, favorite, private, excluded, file_count")
|
||||
|
||||
// Limit result count.
|
||||
if f.Count > 0 && f.Count <= MaxResults {
|
||||
s = s.Limit(f.Count).Offset(f.Offset)
|
||||
} else {
|
||||
s = s.Limit(MaxResults).Offset(f.Offset)
|
||||
}
|
||||
|
||||
// Set sort order.
|
||||
switch f.Order {
|
||||
case "count":
|
||||
s = s.Order("file_count DESC")
|
||||
default:
|
||||
s = s.Order("subject_name")
|
||||
}
|
||||
|
||||
if f.ID != "" {
|
||||
s = s.Where("subject_uid IN (?)", strings.Split(f.ID, Or))
|
||||
|
||||
if result := s.Scan(&results); result.Error != nil {
|
||||
return results, result.Error
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
for _, where := range LikeAnyWord("subject_name", f.Query) {
|
||||
s = s.Where("(?)", gorm.Expr(where))
|
||||
}
|
||||
}
|
||||
|
||||
if f.Type != "" {
|
||||
s = s.Where("subject_type IN (?)", strings.Split(f.Type, Or))
|
||||
}
|
||||
|
||||
if f.Favorite {
|
||||
s = s.Where("favorite = 1")
|
||||
}
|
||||
|
||||
if f.Private {
|
||||
s = s.Where("private = 1")
|
||||
}
|
||||
|
||||
if f.Excluded {
|
||||
s = s.Where("excluded = 1")
|
||||
}
|
||||
|
||||
s = s.Where("deleted_at IS NULL")
|
||||
|
||||
if result := s.Scan(&results); result.Error != nil {
|
||||
return results, result.Error
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
20
internal/query/subject_search_test.go
Normal file
20
internal/query/subject_search_test.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package query
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSubjectSearch(t *testing.T) {
|
||||
t.Run("FindAll", func(t *testing.T) {
|
||||
results, err := SubjectSearch(form.SubjectSearch{Type: entity.SubjectPerson})
|
||||
assert.NoError(t, err)
|
||||
assert.LessOrEqual(t, 3, len(results))
|
||||
})
|
||||
|
||||
}
|
|
@ -86,6 +86,9 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
|||
api.PhotoPrimary(v1)
|
||||
api.PhotoUnstack(v1)
|
||||
|
||||
api.GetSubjects(v1)
|
||||
api.GetSubject(v1)
|
||||
|
||||
api.GetLabels(v1)
|
||||
api.UpdateLabel(v1)
|
||||
api.GetLabelLinks(v1)
|
||||
|
|
Loading…
Reference in a new issue