People: Add mutex so changes don't get processed concurrently

This commit is contained in:
Michael Mayer 2021-12-09 02:33:41 +01:00
parent 986f12af68
commit 1b583e071e
18 changed files with 340 additions and 292 deletions

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-22 17:01+0000\n"
"POT-Creation-Date: 2021-12-09 00:51+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,309 +17,313 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: messages.go:82
#: messages.go:83
msgid "Unexpected error, please try again"
msgstr ""
#: messages.go:83
#: messages.go:84
msgid "Invalid request"
msgstr ""
#: messages.go:84
#: messages.go:85
msgid "Changes could not be saved"
msgstr ""
#: messages.go:85
#: messages.go:86
msgid "Could not be deleted"
msgstr ""
#: messages.go:86
#: messages.go:87
#, c-format
msgid "%s already exists"
msgstr ""
#: messages.go:87
#: messages.go:88
msgid "Not found"
msgstr ""
#: messages.go:88
#: messages.go:89
msgid "File not found"
msgstr ""
#: messages.go:89
#: messages.go:90
msgid "Selection not found"
msgstr ""
#: messages.go:90
#: messages.go:91
msgid "Entity not found"
msgstr ""
#: messages.go:91
#: messages.go:92
msgid "Account not found"
msgstr ""
#: messages.go:92
#: messages.go:93
msgid "User not found"
msgstr ""
#: messages.go:93
#: messages.go:94
msgid "Label not found"
msgstr ""
#: messages.go:94
#: messages.go:95
msgid "Album not found"
msgstr ""
#: messages.go:95
#: messages.go:96
msgid "Subject not found"
msgstr ""
#: messages.go:96
#: messages.go:97
msgid "Person not found"
msgstr ""
#: messages.go:97
#: messages.go:98
msgid "Face not found"
msgstr ""
#: messages.go:98
#: messages.go:99
msgid "Not available in public mode"
msgstr ""
#: messages.go:99
#: messages.go:100
msgid "not available in read-only mode"
msgstr ""
#: messages.go:100
#: messages.go:101
msgid "Please log in and try again"
msgstr ""
#: messages.go:101
#: messages.go:102
msgid "Upload might be offensive"
msgstr ""
#: messages.go:102
#: messages.go:103
msgid "No items selected"
msgstr ""
#: messages.go:103
#: messages.go:104
msgid "Failed creating file, please check permissions"
msgstr ""
#: messages.go:104
#: messages.go:105
msgid "Failed creating folder, please check permissions"
msgstr ""
#: messages.go:105
#: messages.go:106
msgid "Could not connect, please try again"
msgstr ""
#: messages.go:106
#: messages.go:107
msgid "Invalid password, please try again"
msgstr ""
#: messages.go:107
#: messages.go:108
msgid "Feature disabled"
msgstr ""
#: messages.go:108
#: messages.go:109
msgid "No labels selected"
msgstr ""
#: messages.go:109
#: messages.go:110
msgid "No albums selected"
msgstr ""
#: messages.go:110
#: messages.go:111
msgid "No files available for download"
msgstr ""
#: messages.go:111
#: messages.go:112
msgid "Failed to create zip file"
msgstr ""
#: messages.go:112
#: messages.go:113
msgid "Invalid credentials"
msgstr ""
#: messages.go:113
#: messages.go:114
msgid "Invalid link"
msgstr ""
#: messages.go:114
#: messages.go:115
msgid "Invalid name"
msgstr ""
#: messages.go:117
msgid "Changes successfully saved"
msgstr ""
#: messages.go:118
msgid "Album created"
#: messages.go:116
msgid "Busy, please try again later"
msgstr ""
#: messages.go:119
msgid "Album saved"
msgid "Changes successfully saved"
msgstr ""
#: messages.go:120
msgid "Album created"
msgstr ""
#: messages.go:121
msgid "Album saved"
msgstr ""
#: messages.go:122
#, c-format
msgid "Album %s deleted"
msgstr ""
#: messages.go:121
#: messages.go:123
msgid "Album contents cloned"
msgstr ""
#: messages.go:122
#: messages.go:124
msgid "File removed from stack"
msgstr ""
#: messages.go:123
msgid "File deleted"
msgstr ""
#: messages.go:124
#, c-format
msgid "Selection added to %s"
msgstr ""
#: messages.go:125
#, c-format
msgid "One entry added to %s"
msgid "File deleted"
msgstr ""
#: messages.go:126
#, c-format
msgid "%d entries added to %s"
msgid "Selection added to %s"
msgstr ""
#: messages.go:127
#, c-format
msgid "One entry removed from %s"
msgid "One entry added to %s"
msgstr ""
#: messages.go:128
#, c-format
msgid "%d entries removed from %s"
msgid "%d entries added to %s"
msgstr ""
#: messages.go:129
msgid "Account created"
#, c-format
msgid "One entry removed from %s"
msgstr ""
#: messages.go:130
msgid "Account saved"
#, c-format
msgid "%d entries removed from %s"
msgstr ""
#: messages.go:131
msgid "Account deleted"
msgid "Account created"
msgstr ""
#: messages.go:132
msgid "Settings saved"
msgid "Account saved"
msgstr ""
#: messages.go:133
msgid "Password changed"
msgid "Account deleted"
msgstr ""
#: messages.go:134
#, c-format
msgid "Import completed in %d s"
msgid "Settings saved"
msgstr ""
#: messages.go:135
msgid "Import canceled"
msgid "Password changed"
msgstr ""
#: messages.go:136
#, c-format
msgid "Indexing completed in %d s"
msgid "Import completed in %d s"
msgstr ""
#: messages.go:137
msgid "Indexing originals..."
msgid "Import canceled"
msgstr ""
#: messages.go:138
#, c-format
msgid "Indexing files in %s"
msgid "Indexing completed in %d s"
msgstr ""
#: messages.go:139
msgid "Indexing canceled"
msgid "Indexing originals..."
msgstr ""
#: messages.go:140
#, c-format
msgid "Removed %d files and %d photos"
msgid "Indexing files in %s"
msgstr ""
#: messages.go:141
#, c-format
msgid "Moving files from %s"
msgid "Indexing canceled"
msgstr ""
#: messages.go:142
#, c-format
msgid "Copying files from %s"
msgid "Removed %d files and %d photos"
msgstr ""
#: messages.go:143
msgid "Labels deleted"
#, c-format
msgid "Moving files from %s"
msgstr ""
#: messages.go:144
msgid "Label saved"
#, c-format
msgid "Copying files from %s"
msgstr ""
#: messages.go:145
msgid "Subject saved"
msgid "Labels deleted"
msgstr ""
#: messages.go:146
msgid "Subject deleted"
msgid "Label saved"
msgstr ""
#: messages.go:147
msgid "Person saved"
msgid "Subject saved"
msgstr ""
#: messages.go:148
msgid "Person deleted"
msgid "Subject deleted"
msgstr ""
#: messages.go:149
msgid "Person saved"
msgstr ""
#: messages.go:150
msgid "Person deleted"
msgstr ""
#: messages.go:151
#, c-format
msgid "%d files uploaded in %d s"
msgstr ""
#: messages.go:150
#: messages.go:152
msgid "Selection approved"
msgstr ""
#: messages.go:151
#: messages.go:153
msgid "Selection archived"
msgstr ""
#: messages.go:152
#: messages.go:154
msgid "Selection restored"
msgstr ""
#: messages.go:153
#: messages.go:155
msgid "Selection marked as private"
msgstr ""
#: messages.go:154
#: messages.go:156
msgid "Albums deleted"
msgstr ""
#: messages.go:155
#: messages.go:157
#, c-format
msgid "Zip created in %d s"
msgstr ""
#: messages.go:156
#: messages.go:158
msgid "Permanently deleted"
msgstr ""

View file

@ -1902,9 +1902,9 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
},
"node_modules/@types/node": {
"version": "16.11.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz",
"integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw=="
"version": "16.11.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz",
"integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw=="
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@ -1917,12 +1917,12 @@
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
},
"node_modules/@vue/compiler-core": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.23.tgz",
"integrity": "sha512-4ZhiI/orx+7EJ1B+0zjgvXMV2uRN+XBfG06UN2sJfND9rH5gtEQT3QmO4erum1o6Irl7y754W8/KSaDJh4EUQg==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.24.tgz",
"integrity": "sha512-A0SxB2HAggKzP57LDin5gfgWOTwFyGCtQ5MTMNBADnfQYALWnYuC8kMI0DhRSplGTWRvn9Z2DAnG8f35BnojuA==",
"dependencies": {
"@babel/parser": "^7.15.0",
"@vue/shared": "3.2.23",
"@vue/shared": "3.2.24",
"estree-walker": "^2.0.2",
"source-map": "^0.6.1"
}
@ -1936,25 +1936,25 @@
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.23.tgz",
"integrity": "sha512-X2Nw8QFc5lgoK3kio5ktM95nqmLUH+q+N/PbV4kCHzF1avqv/EGLnAhaaF0Iu4bewNvHJAAhhwPZFeoV/22nbw==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.24.tgz",
"integrity": "sha512-KQEm8r0JFsrNNIfbD28pcwMvHpcJcwjVR1XWFcD0yyQ8eREd7IXhT7J6j7iNCSE/TIo78NOvkwbyX+lnIm836w==",
"dependencies": {
"@vue/compiler-core": "3.2.23",
"@vue/shared": "3.2.23"
"@vue/compiler-core": "3.2.24",
"@vue/shared": "3.2.24"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.23.tgz",
"integrity": "sha512-Aw+pb50Q5zTjyvWod8mNKmYZDRGHJBptmNNWE+84ZxrzEztPgMz8cNYIzWGbwcFVkmJlhvioAMvKnB+LM/sjSA==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.24.tgz",
"integrity": "sha512-YGPcIvVJp2qTPkuT6kT43Eo1xjstyY4bmuiSV31my4bQMBFVR26ANmifUSt759Blok71gK0WzfIZHbcOKYOeKA==",
"dependencies": {
"@babel/parser": "^7.15.0",
"@vue/compiler-core": "3.2.23",
"@vue/compiler-dom": "3.2.23",
"@vue/compiler-ssr": "3.2.23",
"@vue/ref-transform": "3.2.23",
"@vue/shared": "3.2.23",
"@vue/compiler-core": "3.2.24",
"@vue/compiler-dom": "3.2.24",
"@vue/compiler-ssr": "3.2.24",
"@vue/ref-transform": "3.2.24",
"@vue/shared": "3.2.24",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7",
"postcss": "^8.1.10",
@ -1970,12 +1970,12 @@
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.23.tgz",
"integrity": "sha512-Bqzn4jFyXPK1Ehqiq7e/czS8n62gtYF1Zfeu0DrR5uv+SBllh7LIvZjZU6+c8qbocAd3/T3I3gn2cZGmnDb6zg==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.24.tgz",
"integrity": "sha512-E1HHShNsGVWXxs68LDOUuI+Bzak9W/Ier/366aKDBFuwvfwgruwq6abhMfj6pSDZpwZ/PXnfliyl/m7qBSq6gw==",
"dependencies": {
"@vue/compiler-dom": "3.2.23",
"@vue/shared": "3.2.23"
"@vue/compiler-dom": "3.2.24",
"@vue/shared": "3.2.24"
}
},
"node_modules/@vue/component-compiler-utils": {
@ -2026,26 +2026,26 @@
}
},
"node_modules/@vue/ref-transform": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.23.tgz",
"integrity": "sha512-gW0GD2PSAs/th7mC7tPB/UwpIQxclbApVtsDtscDmOJXb2+cdu60ny+SuHNgfrlUT/JqWKQHq7jFKO4woxLNaA==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.24.tgz",
"integrity": "sha512-j6oNbsGLvea2rF8GQB9w6q7UFL1So7J+t6ducaMeWPSyjYZ+slWpwPVK6mmyghg5oGqC41R+HC5BV036Y0KhXQ==",
"dependencies": {
"@babel/parser": "^7.15.0",
"@vue/compiler-core": "3.2.23",
"@vue/shared": "3.2.23",
"@vue/compiler-core": "3.2.24",
"@vue/shared": "3.2.24",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7"
}
},
"node_modules/@vue/shared": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.23.tgz",
"integrity": "sha512-U+/Jefa0QfXUF2qVy9Dqlrb6HKJSr9/wJcM66wXmWcTOoqg7hOWzF4qruDle51pyF4x3wMn6TSH54UdjKjCKMA=="
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.24.tgz",
"integrity": "sha512-BUgRiZCkCrqDps5aQ9av05xcge3rn092ztKIh17tHkeEFgP4zfXMQWBA2zfdoCdCEdBL26xtOv+FZYiOp9RUDA=="
},
"node_modules/@vvo/tzdb": {
"version": "6.35.0",
"resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.35.0.tgz",
"integrity": "sha512-leN0YmA9+N7ZotdAGp/MzLcAippUpC6Occ/P4hG6BAn4rDXJ4NMf/yiD2K8RyV41I1zK0EMVxo3ca1WrCq4J5g=="
"version": "6.36.0",
"resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.36.0.tgz",
"integrity": "sha512-t+Hs4PJJLiWYZcf5+19VDEHnSO1KVJ6qp7SmRfYWpuHLCWcSvCeaZGSeEjprEYIW4+2vOqGTmSUZaRzySIVq+A=="
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.1",
@ -3068,9 +3068,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001284",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001284.tgz",
"integrity": "sha512-t28SKa7g6kiIQi6NHeOcKrOrGMzCRrXvlasPwWC26TH2QNdglgzQIRUuJ0cR3NeQPH+5jpuveeeSFDLm2zbkEw==",
"version": "1.0.30001285",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz",
"integrity": "sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
@ -3477,9 +3477,9 @@
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"node_modules/core-js": {
"version": "3.19.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.2.tgz",
"integrity": "sha512-ciYCResnLIATSsXuXnIOH4CbdfgV+H1Ltg16hJFN7/v6OxqnFr/IFGeLacaZ+fHLAm0TBbXwNK9/DNBzBUrO/g==",
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.3.tgz",
"integrity": "sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
@ -3487,9 +3487,9 @@
}
},
"node_modules/core-js-compat": {
"version": "3.19.2",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.2.tgz",
"integrity": "sha512-ObBY1W5vx/LFFMaL1P5Udo4Npib6fu+cMokeziWkA8Tns4FcDemKF5j9JvaI5JhdkW8EQJQGJN1EcrzmEwuAqQ==",
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.3.tgz",
"integrity": "sha512-59tYzuWgEEVU9r+SRgceIGXSSUn47JknoiXW6Oq7RW8QHjXWz3/vp8pa7dbtuVu40sewz3OP3JmQEcDdztrLhA==",
"dependencies": {
"browserslist": "^4.18.1",
"semver": "7.0.0"
@ -4345,9 +4345,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.10.tgz",
"integrity": "sha512-tFgA40Iq2oy4k2PnZrLJowbgpij+lD6ZLxkw8Ht1NKTYyN8dvSvC5xlo8X0WW2jqhKSzITrbr5mpB4/AZ/8OUA=="
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.14.tgz",
"integrity": "sha512-RsGkAN9JEAYMObS72kzUsPPcPGMqX1rBqGuXi9aa4TBKLzICoLf+DAAtd0fVFzrniJqYzpby47gthCUoObfs0Q=="
},
"node_modules/emoji-regex": {
"version": "8.0.0",
@ -5988,9 +5988,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.14.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
"version": "1.14.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==",
"funding": [
{
"type": "individual",
@ -8406,9 +8406,9 @@
}
},
"node_modules/object-inspect": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz",
"integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -8706,12 +8706,9 @@
}
},
"node_modules/pirates": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
"integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==",
"dependencies": {
"node-modules-regexp": "^1.0.0"
},
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz",
"integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==",
"engines": {
"node": ">= 6"
}
@ -10790,9 +10787,9 @@
}
},
"node_modules/prettier": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
"integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"bin": {
"prettier": "bin-prettier.js"
},
@ -11455,9 +11452,9 @@
}
},
"node_modules/sass-loader": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.3.0.tgz",
"integrity": "sha512-6l9qwhdOb7qSrtOu96QQ81LVl8v6Dp9j1w3akOm0aWHyrTYtagDt5+kS32N4yq4hHk3M+rdqoRMH+lIdqvW6HA==",
"version": "12.4.0",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz",
"integrity": "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==",
"dependencies": {
"klona": "^2.0.4",
"neo-async": "^2.6.2"
@ -11471,7 +11468,7 @@
},
"peerDependencies": {
"fibers": ">= 3.1.0",
"node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0",
"node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0",
"sass": "^1.3.0",
"webpack": "^5.0.0"
},
@ -13188,9 +13185,9 @@
}
},
"node_modules/watchpack": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.0.tgz",
"integrity": "sha512-MnN0Q1OsvB/GGHETrFeZPQaOelWh/7O+EiFlj8sM9GPjtQkis7k01aAxrg/18kTfoIVcLL+haEVFlXDaSRwKRw==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
"integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@ -13200,9 +13197,9 @@
}
},
"node_modules/webpack": {
"version": "5.64.4",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.64.4.tgz",
"integrity": "sha512-LWhqfKjCLoYJLKJY8wk2C3h77i8VyHowG3qYNZiIqD6D0ZS40439S/KVuc/PY48jp2yQmy0mhMknq8cys4jFMw==",
"version": "5.65.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz",
"integrity": "sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw==",
"dependencies": {
"@types/eslint-scope": "^3.7.0",
"@types/estree": "^0.0.50",
@ -13226,7 +13223,7 @@
"schema-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.0",
"watchpack": "^2.3.1",
"webpack-sources": "^3.2.2"
},
"bin": {
@ -15017,9 +15014,9 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
},
"@types/node": {
"version": "16.11.11",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.11.tgz",
"integrity": "sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw=="
"version": "16.11.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz",
"integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw=="
},
"@types/parse-json": {
"version": "4.0.0",
@ -15032,12 +15029,12 @@
"integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="
},
"@vue/compiler-core": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.23.tgz",
"integrity": "sha512-4ZhiI/orx+7EJ1B+0zjgvXMV2uRN+XBfG06UN2sJfND9rH5gtEQT3QmO4erum1o6Irl7y754W8/KSaDJh4EUQg==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.24.tgz",
"integrity": "sha512-A0SxB2HAggKzP57LDin5gfgWOTwFyGCtQ5MTMNBADnfQYALWnYuC8kMI0DhRSplGTWRvn9Z2DAnG8f35BnojuA==",
"requires": {
"@babel/parser": "^7.15.0",
"@vue/shared": "3.2.23",
"@vue/shared": "3.2.24",
"estree-walker": "^2.0.2",
"source-map": "^0.6.1"
},
@ -15050,25 +15047,25 @@
}
},
"@vue/compiler-dom": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.23.tgz",
"integrity": "sha512-X2Nw8QFc5lgoK3kio5ktM95nqmLUH+q+N/PbV4kCHzF1avqv/EGLnAhaaF0Iu4bewNvHJAAhhwPZFeoV/22nbw==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.24.tgz",
"integrity": "sha512-KQEm8r0JFsrNNIfbD28pcwMvHpcJcwjVR1XWFcD0yyQ8eREd7IXhT7J6j7iNCSE/TIo78NOvkwbyX+lnIm836w==",
"requires": {
"@vue/compiler-core": "3.2.23",
"@vue/shared": "3.2.23"
"@vue/compiler-core": "3.2.24",
"@vue/shared": "3.2.24"
}
},
"@vue/compiler-sfc": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.23.tgz",
"integrity": "sha512-Aw+pb50Q5zTjyvWod8mNKmYZDRGHJBptmNNWE+84ZxrzEztPgMz8cNYIzWGbwcFVkmJlhvioAMvKnB+LM/sjSA==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.24.tgz",
"integrity": "sha512-YGPcIvVJp2qTPkuT6kT43Eo1xjstyY4bmuiSV31my4bQMBFVR26ANmifUSt759Blok71gK0WzfIZHbcOKYOeKA==",
"requires": {
"@babel/parser": "^7.15.0",
"@vue/compiler-core": "3.2.23",
"@vue/compiler-dom": "3.2.23",
"@vue/compiler-ssr": "3.2.23",
"@vue/ref-transform": "3.2.23",
"@vue/shared": "3.2.23",
"@vue/compiler-core": "3.2.24",
"@vue/compiler-dom": "3.2.24",
"@vue/compiler-ssr": "3.2.24",
"@vue/ref-transform": "3.2.24",
"@vue/shared": "3.2.24",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7",
"postcss": "^8.1.10",
@ -15083,12 +15080,12 @@
}
},
"@vue/compiler-ssr": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.23.tgz",
"integrity": "sha512-Bqzn4jFyXPK1Ehqiq7e/czS8n62gtYF1Zfeu0DrR5uv+SBllh7LIvZjZU6+c8qbocAd3/T3I3gn2cZGmnDb6zg==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.24.tgz",
"integrity": "sha512-E1HHShNsGVWXxs68LDOUuI+Bzak9W/Ier/366aKDBFuwvfwgruwq6abhMfj6pSDZpwZ/PXnfliyl/m7qBSq6gw==",
"requires": {
"@vue/compiler-dom": "3.2.23",
"@vue/shared": "3.2.23"
"@vue/compiler-dom": "3.2.24",
"@vue/shared": "3.2.24"
}
},
"@vue/component-compiler-utils": {
@ -15129,26 +15126,26 @@
}
},
"@vue/ref-transform": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.23.tgz",
"integrity": "sha512-gW0GD2PSAs/th7mC7tPB/UwpIQxclbApVtsDtscDmOJXb2+cdu60ny+SuHNgfrlUT/JqWKQHq7jFKO4woxLNaA==",
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.24.tgz",
"integrity": "sha512-j6oNbsGLvea2rF8GQB9w6q7UFL1So7J+t6ducaMeWPSyjYZ+slWpwPVK6mmyghg5oGqC41R+HC5BV036Y0KhXQ==",
"requires": {
"@babel/parser": "^7.15.0",
"@vue/compiler-core": "3.2.23",
"@vue/shared": "3.2.23",
"@vue/compiler-core": "3.2.24",
"@vue/shared": "3.2.24",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7"
}
},
"@vue/shared": {
"version": "3.2.23",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.23.tgz",
"integrity": "sha512-U+/Jefa0QfXUF2qVy9Dqlrb6HKJSr9/wJcM66wXmWcTOoqg7hOWzF4qruDle51pyF4x3wMn6TSH54UdjKjCKMA=="
"version": "3.2.24",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.24.tgz",
"integrity": "sha512-BUgRiZCkCrqDps5aQ9av05xcge3rn092ztKIh17tHkeEFgP4zfXMQWBA2zfdoCdCEdBL26xtOv+FZYiOp9RUDA=="
},
"@vvo/tzdb": {
"version": "6.35.0",
"resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.35.0.tgz",
"integrity": "sha512-leN0YmA9+N7ZotdAGp/MzLcAippUpC6Occ/P4hG6BAn4rDXJ4NMf/yiD2K8RyV41I1zK0EMVxo3ca1WrCq4J5g=="
"version": "6.36.0",
"resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.36.0.tgz",
"integrity": "sha512-t+Hs4PJJLiWYZcf5+19VDEHnSO1KVJ6qp7SmRfYWpuHLCWcSvCeaZGSeEjprEYIW4+2vOqGTmSUZaRzySIVq+A=="
},
"@webassemblyjs/ast": {
"version": "1.11.1",
@ -15932,9 +15929,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001284",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001284.tgz",
"integrity": "sha512-t28SKa7g6kiIQi6NHeOcKrOrGMzCRrXvlasPwWC26TH2QNdglgzQIRUuJ0cR3NeQPH+5jpuveeeSFDLm2zbkEw=="
"version": "1.0.30001285",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz",
"integrity": "sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q=="
},
"chai": {
"version": "4.3.4",
@ -16264,14 +16261,14 @@
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"core-js": {
"version": "3.19.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.2.tgz",
"integrity": "sha512-ciYCResnLIATSsXuXnIOH4CbdfgV+H1Ltg16hJFN7/v6OxqnFr/IFGeLacaZ+fHLAm0TBbXwNK9/DNBzBUrO/g=="
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.3.tgz",
"integrity": "sha512-LeLBMgEGSsG7giquSzvgBrTS7V5UL6ks3eQlUSbN8dJStlLFiRzUm5iqsRyzUB8carhfKjkJ2vzKqE6z1Vga9g=="
},
"core-js-compat": {
"version": "3.19.2",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.2.tgz",
"integrity": "sha512-ObBY1W5vx/LFFMaL1P5Udo4Npib6fu+cMokeziWkA8Tns4FcDemKF5j9JvaI5JhdkW8EQJQGJN1EcrzmEwuAqQ==",
"version": "3.19.3",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.3.tgz",
"integrity": "sha512-59tYzuWgEEVU9r+SRgceIGXSSUn47JknoiXW6Oq7RW8QHjXWz3/vp8pa7dbtuVu40sewz3OP3JmQEcDdztrLhA==",
"requires": {
"browserslist": "^4.18.1",
"semver": "7.0.0"
@ -16881,9 +16878,9 @@
"integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
},
"electron-to-chromium": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.10.tgz",
"integrity": "sha512-tFgA40Iq2oy4k2PnZrLJowbgpij+lD6ZLxkw8Ht1NKTYyN8dvSvC5xlo8X0WW2jqhKSzITrbr5mpB4/AZ/8OUA=="
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.14.tgz",
"integrity": "sha512-RsGkAN9JEAYMObS72kzUsPPcPGMqX1rBqGuXi9aa4TBKLzICoLf+DAAtd0fVFzrniJqYzpby47gthCUoObfs0Q=="
},
"emoji-regex": {
"version": "8.0.0",
@ -18115,9 +18112,9 @@
}
},
"follow-redirects": {
"version": "1.14.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
"version": "1.14.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A=="
},
"foreach": {
"version": "2.0.5",
@ -19877,9 +19874,9 @@
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-inspect": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz",
"integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA=="
},
"object-keys": {
"version": "1.1.1",
@ -20087,12 +20084,9 @@
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
},
"pirates": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
"integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==",
"requires": {
"node-modules-regexp": "^1.0.0"
}
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz",
"integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw=="
},
"pkg-dir": {
"version": "2.0.0",
@ -21552,9 +21546,9 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
},
"prettier": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz",
"integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg=="
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg=="
},
"prettier-linter-helpers": {
"version": "1.0.0",
@ -22095,9 +22089,9 @@
}
},
"sass-loader": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.3.0.tgz",
"integrity": "sha512-6l9qwhdOb7qSrtOu96QQ81LVl8v6Dp9j1w3akOm0aWHyrTYtagDt5+kS32N4yq4hHk3M+rdqoRMH+lIdqvW6HA==",
"version": "12.4.0",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz",
"integrity": "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==",
"requires": {
"klona": "^2.0.4",
"neo-async": "^2.6.2"
@ -23394,18 +23388,18 @@
}
},
"watchpack": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.0.tgz",
"integrity": "sha512-MnN0Q1OsvB/GGHETrFeZPQaOelWh/7O+EiFlj8sM9GPjtQkis7k01aAxrg/18kTfoIVcLL+haEVFlXDaSRwKRw==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
"integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
"requires": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
}
},
"webpack": {
"version": "5.64.4",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.64.4.tgz",
"integrity": "sha512-LWhqfKjCLoYJLKJY8wk2C3h77i8VyHowG3qYNZiIqD6D0ZS40439S/KVuc/PY48jp2yQmy0mhMknq8cys4jFMw==",
"version": "5.65.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz",
"integrity": "sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw==",
"requires": {
"@types/eslint-scope": "^3.7.0",
"@types/estree": "^0.0.50",
@ -23429,7 +23423,7 @@
"schema-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.0",
"watchpack": "^2.3.1",
"webpack-sources": "^3.2.2"
},
"dependencies": {

View file

@ -133,28 +133,40 @@ export default {
refresh() {
},
onReject(marker) {
if (this.busy || !marker) return;
this.busy = true;
this.$notify.blockUI();
marker.reject().finally(() => {
this.$notify.unblockUI();
this.busy = false;
});
},
onApprove(marker) {
if (this.busy || !marker) return;
this.busy = true;
marker.approve().finally(() => this.busy = false);
},
onClearSubject(marker) {
if (this.busy || !marker) return;
this.busy = true;
this.$notify.blockUI();
marker.clearSubject(marker).finally(() => {
this.$notify.unblockUI();
this.busy = false;
});
},
onRename(marker) {
if (this.busy || !marker) return;
this.busy = true;
this.$notify.blockUI();
marker.rename().finally(() => {
this.$notify.unblockUI();
this.busy = false;

View file

@ -452,7 +452,7 @@ export default {
return params;
},
refresh() {
if (this.loading || !this.active) {
if (this.loading || !this.active || this.busy) {
return;
}
@ -501,6 +501,8 @@ export default {
});
},
onShow(model) {
if (this.busy || !model) return;
this.busy = true;
model.show().finally(() => {
this.busy = false;
@ -508,6 +510,8 @@ export default {
});
},
onHide(model) {
if (this.busy || !model) return;
this.busy = true;
model.hide().finally(() => {
this.busy = false;
@ -515,9 +519,7 @@ export default {
});
},
toggleHidden(model) {
if (!model) {
return;
}
if (this.busy || !model) return;
this.busy = true;
@ -532,8 +534,8 @@ export default {
});
},
onRename(model) {
if (!model.Name || model.Name.trim() === "") {
// Refuse to save empty name.
if (this.busy || !model || !model.Name || model.Name.trim() === "") {
// Ignore if busy, refuse to save empty name.
return;
}

View file

@ -111,3 +111,7 @@ func AbortAlreadyExists(c *gin.Context, s string) {
func AbortFeatureDisabled(c *gin.Context) {
Abort(c, http.StatusForbidden, i18n.ErrFeatureDisabled)
}
func AbortBusy(c *gin.Context) {
Abort(c, http.StatusTooManyRequests, i18n.ErrBusy)
}

View file

@ -12,6 +12,7 @@ import (
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/i18n"
"github.com/photoprism/photoprism/internal/mutex"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/service"
)
@ -66,6 +67,13 @@ func findFileMarker(c *gin.Context) (file *entity.File, marker *entity.Marker, e
// id: int Marker ID as returned by the API
func UpdateMarker(router *gin.RouterGroup) {
router.PUT("/markers/:marker_uid", func(c *gin.Context) {
if err := mutex.People.Start(); err != nil {
AbortBusy(c)
return
}
defer mutex.People.Stop()
file, marker, err := findFileMarker(c)
if err != nil {
@ -137,6 +145,13 @@ func UpdateMarker(router *gin.RouterGroup) {
// id: int Marker ID as returned by the API
func ClearMarkerSubject(router *gin.RouterGroup) {
router.DELETE("/markers/:marker_uid/subject", func(c *gin.Context) {
if err := mutex.People.Start(); err != nil {
AbortBusy(c)
return
}
defer mutex.People.Stop()
file, marker, err := findFileMarker(c)
if err != nil {

View file

@ -10,6 +10,7 @@ import (
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/i18n"
"github.com/photoprism/photoprism/internal/mutex"
"github.com/photoprism/photoprism/pkg/txt"
)
@ -39,6 +40,13 @@ func GetSubject(router *gin.RouterGroup) {
// PUT /api/v1/subjects/:uid
func UpdateSubject(router *gin.RouterGroup) {
router.PUT("/subjects/:uid", func(c *gin.Context) {
if err := mutex.People.Start(); err != nil {
AbortBusy(c)
return
}
defer mutex.People.Stop()
s := Auth(SessionID(c), acl.ResourceSubjects, acl.ActionUpdate)
if s.Invalid() {

View file

@ -446,10 +446,12 @@ func (c *Config) LogLevel() logrus.Level {
// Shutdown services and workers.
func (c *Config) Shutdown() {
mutex.People.Cancel()
mutex.MainWorker.Cancel()
mutex.ShareWorker.Cancel()
mutex.SyncWorker.Cancel()
mutex.MetaWorker.Cancel()
mutex.FacesWorker.Cancel()
if err := c.CloseDb(); err != nil {
log.Errorf("could not close database connection: %s", err)

View file

@ -18,7 +18,7 @@ import (
"github.com/urfave/cli"
)
// define constants used for testing the config package
// Download URL and ZIP hash for test files.
const (
TestDataZip = "/tmp/photoprism/testdata.zip"
TestDataURL = "https://dl.photoprism.org/qa/testdata.zip"
@ -28,12 +28,13 @@ const (
var testConfig *Config
var testConfigOnce sync.Once
var testConfigMutex sync.Mutex
var testDataMutex sync.Mutex
func testDataPath(assetsPath string) string {
return assetsPath + "/testdata"
}
// NewTestOptions inits valid options used for testing
// NewTestOptions returns valid config options for tests.
func NewTestOptions() *Options {
assetsPath := fs.Abs("../../assets")
storagePath := fs.Abs("../../storage")
@ -80,7 +81,7 @@ func NewTestOptions() *Options {
return c
}
// NewTestOptionsError inits invalid options used for testing
// NewTestOptionsError returns invalid config options for tests.
func NewTestOptionsError() *Options {
assetsPath := fs.Abs("../..")
testDataPath := fs.Abs("../../storage/testdata")
@ -104,14 +105,14 @@ func SetNewTestConfig() {
testConfig = NewTestConfig()
}
// TestConfig inits the global testConfig if it was not already initialised
// TestConfig returns the existing test config instance or creates a new instance and returns it.
func TestConfig() *Config {
testConfigOnce.Do(SetNewTestConfig)
return testConfig
}
// NewTestConfig inits valid config used for testing
// NewTestConfig returns a valid test config.
func NewTestConfig() *Config {
defer log.Debug(capture.Time(time.Now(), "config: new test config created"))
@ -147,14 +148,14 @@ func NewTestConfig() *Config {
return c
}
// NewTestErrorConfig inits invalid config used for testing
// NewTestErrorConfig returns an invalid test config.
func NewTestErrorConfig() *Config {
c := &Config{options: NewTestOptionsError()}
return c
}
// CliTestContext returns example cli config for testing
// CliTestContext returns a CLI context for testing.
func CliTestContext() *cli.Context {
config := NewTestOptions()
@ -200,7 +201,7 @@ func CliTestContext() *cli.Context {
return c
}
// RemoveTestData deletes files in import, export, originals and cache folders
// RemoveTestData deletes files in import, export, originals, and cache folders.
func (c *Config) RemoveTestData(t *testing.T) {
if err := os.RemoveAll(c.ImportPath()); err != nil {
t.Fatal(err)
@ -219,7 +220,7 @@ func (c *Config) RemoveTestData(t *testing.T) {
}
}
// DownloadTestData downloads test data from photoprism.org server
// DownloadTestData downloads the test files from the file server.
func (c *Config) DownloadTestData(t *testing.T) {
if fs.FileExists(TestDataZip) {
hash := fs.Hash(TestDataZip)
@ -242,20 +243,23 @@ func (c *Config) DownloadTestData(t *testing.T) {
}
}
// UnzipTestData in default test folder
// UnzipTestData extracts tests files from the zip archive.
func (c *Config) UnzipTestData(t *testing.T) {
if _, err := fs.Unzip(TestDataZip, c.StoragePath()); err != nil {
t.Fatalf("config: could not unzip test data: %s", err.Error())
}
}
// InitializeTestData using testing constant
// InitializeTestData resets the test file directory.
func (c *Config) InitializeTestData(t *testing.T) {
defer t.Logf(capture.Time(time.Now(), "config: initialized test data"))
testDataMutex.Lock()
defer testDataMutex.Unlock()
start := time.Now()
c.RemoveTestData(t)
c.DownloadTestData(t)
c.UnzipTestData(t)
t.Logf("config: initialized test data [%s]", time.Since(start))
}

View file

@ -49,8 +49,8 @@ func LabelCounts() LabelPhotoCounts {
// UpdatePlacesCounts updates the places photo counts.
func UpdatePlacesCounts() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
@ -73,8 +73,8 @@ func UpdatePlacesCounts() (err error) {
// UpdateSubjectCounts updates the subject file counts.
func UpdateSubjectCounts() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
@ -128,8 +128,8 @@ func UpdateSubjectCounts() (err error) {
// UpdateLabelCounts updates the label photo counts.
func UpdateLabelCounts() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
var res *gorm.DB

View file

@ -34,6 +34,7 @@ const (
ErrInvalidCredentials
ErrInvalidLink
ErrInvalidName
ErrBusy
MsgChangesSaved
MsgAlbumCreated
@ -112,6 +113,7 @@ var Messages = MessageMap{
ErrInvalidCredentials: gettext("Invalid credentials"),
ErrInvalidLink: gettext("Invalid link"),
ErrInvalidName: gettext("Invalid name"),
ErrBusy: gettext("Busy, please try again later"),
// Info and confirmation messages:
MsgChangesSaved: gettext("Changes successfully saved"),

View file

@ -6,7 +6,8 @@ import (
var (
Db = sync.Mutex{}
IndexUpdate = sync.Mutex{}
Index = sync.Mutex{}
People = Busy{}
MainWorker = Busy{}
SyncWorker = Busy{}
ShareWorker = Busy{}

View file

@ -74,8 +74,8 @@ func AlbumCoverByUID(uid string) (file entity.File, err error) {
// UpdateAlbumDates updates album year, month and day based on indexed photo metadata.
func UpdateAlbumDates() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
switch DbDialect() {
case MySQL:
@ -93,8 +93,8 @@ func UpdateAlbumDates() error {
// UpdateMissingAlbumEntries sets a flag for missing photo album entries.
func UpdateMissingAlbumEntries() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
switch DbDialect() {
default:

View file

@ -14,8 +14,8 @@ import (
// UpdateAlbumDefaultCovers updates default album cover thumbs.
func UpdateAlbumDefaultCovers() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
@ -62,8 +62,8 @@ func UpdateAlbumDefaultCovers() (err error) {
// UpdateAlbumFolderCovers updates folder album cover thumbs.
func UpdateAlbumFolderCovers() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
@ -110,8 +110,8 @@ func UpdateAlbumFolderCovers() (err error) {
// UpdateAlbumMonthCovers updates month album cover thumbs.
func UpdateAlbumMonthCovers() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
@ -178,8 +178,8 @@ func UpdateAlbumCovers() (err error) {
// UpdateLabelCovers updates label cover thumbs.
func UpdateLabelCovers() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
@ -245,8 +245,8 @@ func UpdateLabelCovers() (err error) {
// UpdateSubjectCovers updates subject cover thumbs.
func UpdateSubjectCovers() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()

View file

@ -213,8 +213,8 @@ func ResolveFaceCollisions() (conflicts, resolved int, err error) {
// RemovePeopleAndFaces permanently removes all people, faces, and face markers.
func RemovePeopleAndFaces() (err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
// Delete people.
if err = UnscopedDb().Delete(entity.Subject{}, "subj_type = ?", entity.SubjPerson).Error; err != nil {

View file

@ -64,8 +64,8 @@ func AlbumFolders(threshold int) (folders entity.Folders, err error) {
// UpdateFolderDates updates folder year, month and day based on indexed photo metadata.
func UpdateFolderDates() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
switch DbDialect() {
case MySQL:

View file

@ -118,8 +118,8 @@ func OrphanPhotos() (photos entity.Photos, err error) {
// FixPrimaries tries to set a primary file for photos that have none.
func FixPrimaries() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()
@ -162,8 +162,8 @@ func FixPrimaries() error {
// FlagHiddenPhotos sets the quality score of photos without valid primary file to -1.
func FlagHiddenPhotos() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
start := time.Now()

View file

@ -44,8 +44,8 @@ func PurgeOrphans() error {
// PurgeOrphanFiles removes files without a photo from the index.
func PurgeOrphanFiles() (count int, err error) {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
files, err := OrphanFiles()
@ -66,8 +66,8 @@ func PurgeOrphanFiles() (count int, err error) {
// PurgeOrphanDuplicates deletes all files from the duplicates table that don't exist in the files table.
func PurgeOrphanDuplicates() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
return UnscopedDb().Delete(
entity.Duplicate{},
@ -76,8 +76,8 @@ func PurgeOrphanDuplicates() error {
// PurgeOrphanCountries removes countries without any photos.
func PurgeOrphanCountries() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
entity.FlushCountryCache()
switch DbDialect() {
@ -88,8 +88,8 @@ func PurgeOrphanCountries() error {
// PurgeOrphanCameras removes cameras without any photos.
func PurgeOrphanCameras() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
entity.FlushCameraCache()
switch DbDialect() {
@ -100,8 +100,8 @@ func PurgeOrphanCameras() error {
// PurgeOrphanLenses removes cameras without any photos.
func PurgeOrphanLenses() error {
mutex.IndexUpdate.Lock()
defer mutex.IndexUpdate.Unlock()
mutex.Index.Lock()
defer mutex.Index.Unlock()
entity.FlushLensCache()
switch DbDialect() {