Added versioning, cleaned up API documentation, fixed endpoints, resolved logout diplay update issue

This commit is contained in:
ReAnzu 2018-02-26 21:47:01 -06:00
parent d0b423e91c
commit 22cf806220
7 changed files with 66 additions and 16 deletions

33
API.md
View file

@ -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.

View file

@ -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'));
}

View file

@ -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

View file

@ -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:

View file

@ -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],

View file

@ -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')
)

View file

@ -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')