فهرست منبع

OpenAPI: document that quota-update support partial updates

If the update mode is "add" and you pass only used_quota_size or only
used_quota_files the missing field will remain unchanged
Nicola Murino 4 سال پیش
والد
کامیت
00f97aabb4
4فایلهای تغییر یافته به همراه42 افزوده شده و 8 حذف شده
  1. 3 3
      examples/bulkupdate/bulkuserupdate
  2. 5 4
      examples/quotascan/scanuserquota
  3. 32 0
      httpd/httpd_test.go
  4. 2 1
      httpd/schema/openapi.yaml

+ 3 - 3
examples/bulkupdate/bulkuserupdate

@@ -24,7 +24,7 @@ fields_to_update = {"status":0, "quota_files": 1000, "additional_info":"updated
 
 
 # get a JWT token
 # get a JWT token
 auth = requests.auth.HTTPBasicAuth(admin_user, admin_password)
 auth = requests.auth.HTTPBasicAuth(admin_user, admin_password)
-r = requests.get(urlparse.urljoin(base_url, "api/v2/token"), auth=auth, verify=verify_tls_cert)
+r = requests.get(urlparse.urljoin(base_url, "api/v2/token"), auth=auth, verify=verify_tls_cert, timeout=10)
 if r.status_code != 200:
 if r.status_code != 200:
 	print("error getting access token: {}".format(r.text))
 	print("error getting access token: {}".format(r.text))
 	sys.exit(1)
 	sys.exit(1)
@@ -33,14 +33,14 @@ auth_header = {"Authorization": "Bearer " + access_token}
 
 
 for username in users_to_update:
 for username in users_to_update:
 	r = requests.get(urlparse.urljoin(base_url, posixpath.join("api/v2/users", username)),
 	r = requests.get(urlparse.urljoin(base_url, posixpath.join("api/v2/users", username)),
-					headers=auth_header, verify=verify_tls_cert)
+					headers=auth_header, verify=verify_tls_cert, timeout=10)
 	if r.status_code != 200:
 	if r.status_code != 200:
 		print("error getting user {}: {}".format(username, r.text))
 		print("error getting user {}: {}".format(username, r.text))
 		continue
 		continue
 	user = r.json()
 	user = r.json()
 	user.update(fields_to_update)
 	user.update(fields_to_update)
 	r = requests.put(urlparse.urljoin(base_url, posixpath.join("api/v2/users", username)),
 	r = requests.put(urlparse.urljoin(base_url, posixpath.join("api/v2/users", username)),
-					headers=auth_header, verify=verify_tls_cert, json=user)
+					headers=auth_header, verify=verify_tls_cert, json=user, timeout=10)
 	if r.status_code == 200:
 	if r.status_code == 200:
 		print("user {} updated".format(username))
 		print("user {} updated".format(username))
 	else:
 	else:

+ 5 - 4
examples/quotascan/scanuserquota

@@ -50,7 +50,7 @@ class UpdateQuota:
 				return
 				return
 
 
 		auth = requests.auth.HTTPBasicAuth(admin_user, admin_password)
 		auth = requests.auth.HTTPBasicAuth(admin_user, admin_password)
-		r = requests.get(urlparse.urljoin(base_url, "api/v2/token"), auth=auth, verify=verify_tls_cert)
+		r = requests.get(urlparse.urljoin(base_url, "api/v2/token"), auth=auth, verify=verify_tls_cert, timeout=10)
 		if r.status_code != 200:
 		if r.status_code != 200:
 			self.printLog("error getting access token: {}".format(r.text))
 			self.printLog("error getting access token: {}".format(r.text))
 			sys.exit(1)
 			sys.exit(1)
@@ -65,7 +65,8 @@ class UpdateQuota:
 	def waitForQuotaUpdate(self, username):
 	def waitForQuotaUpdate(self, username):
 		while True:
 		while True:
 			auth_header = self.getAuthHeader()
 			auth_header = self.getAuthHeader()
-			r = requests.get(urlparse.urljoin(base_url, "api/v2/quota-scans"), headers=auth_header, verify=verify_tls_cert)
+			r = requests.get(urlparse.urljoin(base_url, "api/v2/quota-scans"), headers=auth_header, verify=verify_tls_cert,
+							timeout=10)
 			if r.status_code != 200:
 			if r.status_code != 200:
 				self.printLog("error getting quota scans while waiting for {}: {}".format(username, r.text))
 				self.printLog("error getting quota scans while waiting for {}: {}".format(username, r.text))
 				sys.exit(1)
 				sys.exit(1)
@@ -85,7 +86,7 @@ class UpdateQuota:
 		self.printLog("starting quota update for user {}".format(username))
 		self.printLog("starting quota update for user {}".format(username))
 		auth_header = self.getAuthHeader()
 		auth_header = self.getAuthHeader()
 		r = requests.post(urlparse.urljoin(base_url, "api/v2/quota-scans"), headers=auth_header,
 		r = requests.post(urlparse.urljoin(base_url, "api/v2/quota-scans"), headers=auth_header,
-						json={"username":username}, verify=verify_tls_cert)
+						json={"username":username}, verify=verify_tls_cert, timeout=10)
 		if r.status_code != 202:
 		if r.status_code != 202:
 			self.printLog("error starting quota scan for user {}: {}".format(username, r.text))
 			self.printLog("error starting quota scan for user {}: {}".format(username, r.text))
 			sys.exit(1)
 			sys.exit(1)
@@ -97,7 +98,7 @@ class UpdateQuota:
 			auth_header = self.getAuthHeader()
 			auth_header = self.getAuthHeader()
 			payload = {"limit":self.limit, "offset":self.offset}
 			payload = {"limit":self.limit, "offset":self.offset}
 			r = requests.get(urlparse.urljoin(base_url, "api/v2/users"), headers=auth_header, params=payload,
 			r = requests.get(urlparse.urljoin(base_url, "api/v2/users"), headers=auth_header, params=payload,
-						verify=verify_tls_cert)
+						verify=verify_tls_cert, timeout=10)
 			if r.status_code != 200:
 			if r.status_code != 200:
 				self.printLog("error getting users: {}".format(r.text))
 				self.printLog("error getting users: {}".format(r.text))
 				sys.exit(1)
 				sys.exit(1)

+ 32 - 0
httpd/httpd_test.go

@@ -3596,6 +3596,7 @@ func TestUpdateUserQuotaUsageMock(t *testing.T) {
 	usedQuotaSize := int64(65535)
 	usedQuotaSize := int64(65535)
 	u.UsedQuotaFiles = usedQuotaFiles
 	u.UsedQuotaFiles = usedQuotaFiles
 	u.UsedQuotaSize = usedQuotaSize
 	u.UsedQuotaSize = usedQuotaSize
+	u.QuotaFiles = 100
 	userAsJSON := getUserAsJSON(t, u)
 	userAsJSON := getUserAsJSON(t, u)
 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 	req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
 	setBearerForReq(req, token)
 	setBearerForReq(req, token)
@@ -3615,6 +3616,37 @@ func TestUpdateUserQuotaUsageMock(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
 	assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
 	assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
 	assert.Equal(t, usedQuotaSize, user.UsedQuotaSize)
+	// now update only quota size
+	u.UsedQuotaFiles = 0
+	userAsJSON = getUserAsJSON(t, u)
+	req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaPath+"?mode=add", bytes.NewBuffer(userAsJSON))
+	setBearerForReq(req, token)
+	rr = executeRequest(req)
+	checkResponseCode(t, http.StatusOK, rr)
+	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
+	setBearerForReq(req, token)
+	rr = executeRequest(req)
+	checkResponseCode(t, http.StatusOK, rr)
+	err = render.DecodeJSON(rr.Body, &user)
+	assert.NoError(t, err)
+	assert.Equal(t, usedQuotaFiles, user.UsedQuotaFiles)
+	assert.Equal(t, usedQuotaSize*2, user.UsedQuotaSize)
+	// only quota files
+	u.UsedQuotaFiles = usedQuotaFiles
+	u.UsedQuotaSize = 0
+	userAsJSON = getUserAsJSON(t, u)
+	req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaPath+"?mode=add", bytes.NewBuffer(userAsJSON))
+	setBearerForReq(req, token)
+	rr = executeRequest(req)
+	checkResponseCode(t, http.StatusOK, rr)
+	req, _ = http.NewRequest(http.MethodGet, path.Join(userPath, user.Username), nil)
+	setBearerForReq(req, token)
+	rr = executeRequest(req)
+	checkResponseCode(t, http.StatusOK, rr)
+	err = render.DecodeJSON(rr.Body, &user)
+	assert.NoError(t, err)
+	assert.Equal(t, usedQuotaFiles*2, user.UsedQuotaFiles)
+	assert.Equal(t, usedQuotaSize*2, user.UsedQuotaSize)
 	req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaPath, bytes.NewBuffer([]byte("string")))
 	req, _ = http.NewRequest(http.MethodPut, updateUsedQuotaPath, bytes.NewBuffer([]byte("string")))
 	setBearerForReq(req, token)
 	setBearerForReq(req, token)
 	rr = executeRequest(req)
 	rr = executeRequest(req)

+ 2 - 1
httpd/schema/openapi.yaml

@@ -14,6 +14,7 @@ info:
   description: SFTPGo REST API
   description: SFTPGo REST API
   version: 2.0.5
   version: 2.0.5
   contact:
   contact:
+    name: API support
     url: 'https://github.com/drakkan/sftpgo'
     url: 'https://github.com/drakkan/sftpgo'
   license:
   license:
     name: AGPLv3
     name: AGPLv3
@@ -375,7 +376,7 @@ paths:
             example: reset
             example: reset
       requestBody:
       requestBody:
         required: true
         required: true
-        description: 'The only user mandatory fields are username, used_quota_size and used_quota_files. Please note that if the quota fields are missing they will default to 0'
+        description: 'The only user mandatory fields are username, used_quota_size and used_quota_files. Please note that if the quota fields are missing they will default to 0, this means that if mode is "add" the current value will remain unchanged, if mode is "reset" the missing field is set to 0'
         content:
         content:
           application/json:
           application/json:
             schema:
             schema: