Added versioning, cleaned up API documentation, fixed endpoints, resolved logout diplay update issue
This commit is contained in:
parent
d0b423e91c
commit
22cf806220
7 changed files with 66 additions and 16 deletions
33
API.md
33
API.md
|
@ -60,6 +60,7 @@
|
|||
- User Tokens
|
||||
- [Listing tokens](#listing-tokens)
|
||||
- [Creating token](#creating-token)
|
||||
- [Updating token](#updating-token)
|
||||
- [Deleting token](#deleting-token)
|
||||
- Password reset
|
||||
- [Password reset - step 1: mail request](#password-reset---step-2-confirmation)
|
||||
|
@ -1535,6 +1536,36 @@ data.
|
|||
|
||||
Creates a new user token that can be used for authentication of api
|
||||
endpoints instead of a password.
|
||||
|
||||
## Updating user
|
||||
- **Request**
|
||||
|
||||
`PUT /user-token/<token>`
|
||||
|
||||
- **Input**
|
||||
|
||||
```json5
|
||||
{
|
||||
"version": <version>,
|
||||
"enabled": <enabled>, // optional
|
||||
}
|
||||
```
|
||||
|
||||
- **Output**
|
||||
|
||||
A [user token resource](#user-token).
|
||||
|
||||
- **Errors**
|
||||
|
||||
- the version is outdated
|
||||
- the user token does not exist
|
||||
- privileges are too low
|
||||
|
||||
- **Description**
|
||||
|
||||
Updates an existing user token using specified parameters. All fields
|
||||
except the [`version`](#versioning) are optional - update concerns only
|
||||
provided fields.
|
||||
|
||||
## Deleting token
|
||||
- **Request**
|
||||
|
@ -1806,6 +1837,7 @@ A single user token.
|
|||
"user": <user>,
|
||||
"token": <token>,
|
||||
"enabled": <enabled>,
|
||||
"version": <version>,
|
||||
"creationTime": <creation-time>,
|
||||
"lastEditTime": <last-edit-time>,
|
||||
}
|
||||
|
@ -1815,6 +1847,7 @@ A single user token.
|
|||
- `<user>`: micro user. See [micro user](#micro-user).
|
||||
- `<token>`: the token that can be used to authenticate the user.
|
||||
- `<enabled>`: whether the token is still valid for authentication.
|
||||
- `<version>`: resource version. See [versioning](#versioning).
|
||||
- `<creation-time>`: time the user token was created , formatted as per RFC 3339.
|
||||
- `<last-edit-time>`: time the user token was edited, formatted as per RFC 3339.
|
||||
|
||||
|
|
|
@ -118,9 +118,9 @@ class Api extends events.EventTarget {
|
|||
});
|
||||
}
|
||||
|
||||
get_token(userName, options) {
|
||||
create_token(userName, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.post('/user-tokens', {})
|
||||
this.post('/user-token', {})
|
||||
.then(response => {
|
||||
cookies.set(
|
||||
'auth',
|
||||
|
@ -137,15 +137,14 @@ class Api extends events.EventTarget {
|
|||
|
||||
delete_token(userName, userToken) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.delete('/user-tokens/' + userToken, {})
|
||||
this.delete('/user-token/' + userToken, {})
|
||||
.then(response => {
|
||||
const options = {};
|
||||
cookies.set(
|
||||
'auth',
|
||||
{'user': userName, 'token': null},
|
||||
options);
|
||||
this.userName = userName;
|
||||
this.userToken = null;
|
||||
resolve();
|
||||
}, error => {
|
||||
reject(error);
|
||||
});
|
||||
|
@ -163,7 +162,7 @@ class Api extends events.EventTarget {
|
|||
if (doRemember) {
|
||||
options.expires = 365;
|
||||
}
|
||||
this.get_token(this.userName, options);
|
||||
this.create_token(this.userName, options);
|
||||
this.user = response;
|
||||
resolve();
|
||||
this.dispatchEvent(new CustomEvent('login'));
|
||||
|
@ -175,18 +174,20 @@ class Api extends events.EventTarget {
|
|||
}
|
||||
|
||||
logout() {
|
||||
this.delete_token(this.userName, this.userToken).then(response => {
|
||||
this._logout()
|
||||
}, error => {
|
||||
this._logout()
|
||||
});
|
||||
|
||||
let self = this;
|
||||
this.delete_token(this.userName, this.userToken)
|
||||
.then(response => {
|
||||
self._logout();
|
||||
}, error => {
|
||||
self._logout();
|
||||
});
|
||||
}
|
||||
|
||||
_logout() {
|
||||
this.user = null;
|
||||
this.userName = null;
|
||||
this.userPassword = null;
|
||||
this.userToken = null;
|
||||
this.dispatchEvent(new CustomEvent('logout'));
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ privileges:
|
|||
|
||||
'user_token:list': regular
|
||||
'user_token:create': regular
|
||||
'user_token:edit': regular
|
||||
'user_token:delete': regular
|
||||
|
||||
'posts:create:anonymous': regular
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from typing import Dict
|
||||
|
||||
from szurubooru import model, rest
|
||||
from szurubooru.func import auth, user_tokens, serialization
|
||||
from szurubooru.func import auth, user_tokens, serialization, versions
|
||||
|
||||
|
||||
def _serialize(
|
||||
|
@ -21,15 +21,24 @@ def get_user_tokens(ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Res
|
|||
}
|
||||
|
||||
|
||||
@rest.routes.post('/user-tokens/?')
|
||||
@rest.routes.post('/user-token/?')
|
||||
def create_user_token(ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Response:
|
||||
auth.verify_privilege(ctx.user, 'user_token:create')
|
||||
user_token = user_tokens.create_user_token(ctx.user)
|
||||
return _serialize(ctx, user_token)
|
||||
|
||||
|
||||
@rest.routes.delete('/user-tokens/(?P<user_token>[^/]+)/?')
|
||||
def create_user_token(ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
|
||||
@rest.routes.put('/user-token/(?P<user_token>[^/]+)/?')
|
||||
def edit_user_token(ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Response:
|
||||
auth.verify_privilege(ctx.user, 'user_token:edit')
|
||||
user_token = user_tokens.get_user_token_by_user_and_token(ctx.user, params['user_token'])
|
||||
versions.verify_version(user_token, ctx)
|
||||
versions.bump_version(user_token)
|
||||
return _serialize(ctx, user_token)
|
||||
|
||||
|
||||
@rest.routes.delete('/user-token/(?P<user_token>[^/]+)/?')
|
||||
def delete_user_token(ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
|
||||
auth.verify_privilege(ctx.user, 'user_token:delete')
|
||||
user_token = user_tokens.get_user_token_by_user_and_token(ctx.user, params['user_token'])
|
||||
if user_token is not None:
|
||||
|
|
|
@ -20,6 +20,7 @@ class UserTokenSerializer(serialization.BaseSerializer):
|
|||
'user': self.serialize_user,
|
||||
'token': self.serialize_token,
|
||||
'enabled': self.serialize_enabled,
|
||||
'version': self.serialize_version,
|
||||
'creationTime': self.serialize_creation_time,
|
||||
'lastLoginTime': self.serialize_last_edit_time,
|
||||
}
|
||||
|
@ -39,6 +40,9 @@ class UserTokenSerializer(serialization.BaseSerializer):
|
|||
def serialize_enabled(self) -> Any:
|
||||
return self.user_token.enabled
|
||||
|
||||
def serialize_version(self) -> Any:
|
||||
return self.user_token.version
|
||||
|
||||
|
||||
def serialize_user_token(
|
||||
user_token: Optional[model.UserToken],
|
||||
|
|
|
@ -23,6 +23,7 @@ def upgrade():
|
|||
sa.Column('enabled', sa.Boolean(), nullable=False),
|
||||
sa.Column('creation_time', sa.DateTime(), nullable=False),
|
||||
sa.Column('last_edit_time', sa.DateTime(), nullable=True),
|
||||
sa.Column('version', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
|
|
|
@ -100,5 +100,6 @@ class UserToken(Base):
|
|||
enabled = sa.Column('enabled', sa.Boolean, nullable=False, default=True)
|
||||
creation_time = sa.Column('creation_time', sa.DateTime, nullable=False)
|
||||
last_edit_time = sa.Column('last_edit_time', sa.DateTime)
|
||||
version = sa.Column('version', sa.Integer, default=1, nullable=False)
|
||||
|
||||
user = sa.orm.relationship('User')
|
||||
|
|
Loading…
Reference in a new issue