mirror of https://gitlab.com/litecord/litecord.git
admin_api.features: make features input as a list
- add PATCH /:id/features - enums: add Feature enum - schemas: add FEATURES - storage: add Storage.guild_features - types: add return type to timestamp_
This commit is contained in:
parent
073f47e0f5
commit
2c1c384409
|
|
@ -17,33 +17,75 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from quart import Blueprint, current_app as app
|
from quart import Blueprint, current_app as app, jsonify, request
|
||||||
|
|
||||||
from litecord.auth import admin_check
|
from litecord.auth import admin_check
|
||||||
from litecord.errors import BadRequest
|
from litecord.errors import BadRequest
|
||||||
|
from litecord.schemas import validate, FEATURES
|
||||||
|
from litecord.enums import Feature
|
||||||
|
|
||||||
bp = Blueprint('features_admin', __name__)
|
bp = Blueprint('features_admin', __name__)
|
||||||
|
|
||||||
FEATURES = [
|
|
||||||
''
|
|
||||||
]
|
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/<feature>', methods=['PUT'])
|
async def _features(guild_id: int):
|
||||||
async def insert_feature(guild_id: int, feature: str):
|
return jsonify({
|
||||||
|
'features': await app.storage.guild_features(guild_id)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
async def _update_features(guild_id: int, features: list):
|
||||||
|
await app.db.execute("""
|
||||||
|
UPDATE guilds
|
||||||
|
SET features = $1
|
||||||
|
WHERE id = $2
|
||||||
|
""", features, guild_id)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:guild_id>/features', methods=['PATCH'])
|
||||||
|
async def replace_features(guild_id: int):
|
||||||
|
"""Replace the feature list in a guild"""
|
||||||
|
await admin_check()
|
||||||
|
j = validate(await request.get_json(), FEATURES)
|
||||||
|
features = j['features']
|
||||||
|
|
||||||
|
# yes, we need to pass it to a set and then to a list before
|
||||||
|
# doing anything, since the api client might just
|
||||||
|
# shove 200 repeated features to us.
|
||||||
|
await _update_features(guild_id, list(set(features)))
|
||||||
|
return await _features(guild_id)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:guild_id>/features', methods=['PUT'])
|
||||||
|
async def insert_features(guild_id: int):
|
||||||
"""Insert a feature on a guild."""
|
"""Insert a feature on a guild."""
|
||||||
await admin_check()
|
await admin_check()
|
||||||
|
j = validate(await request.get_json(), FEATURES)
|
||||||
|
|
||||||
# TODO
|
to_add = j['features']
|
||||||
if feature not in FEATURES:
|
features = await app.storage.guild_features(guild_id)
|
||||||
raise BadRequest('invalid feature')
|
features = set(features)
|
||||||
|
|
||||||
return '', 204
|
# i'm assuming set.add is mostly safe
|
||||||
|
for feature in to_add:
|
||||||
|
features.add(feature)
|
||||||
|
|
||||||
|
await _update_features(guild_id, list(features))
|
||||||
|
return await _features(guild_id)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/<feature>', methods=['DELETE'])
|
@bp.route('/<int:guild_id>/<feature>', methods=['DELETE'])
|
||||||
async def remove_feature(guild_id: int, feature: str):
|
async def remove_feature(guild_id: int):
|
||||||
"""Remove a feature from a guild"""
|
"""Remove a feature from a guild"""
|
||||||
await admin_check()
|
await admin_check()
|
||||||
# TODO
|
j = validate(await request.get_json(), FEATURES)
|
||||||
await app.db
|
to_remove = j['features']
|
||||||
return '', 204
|
features = await app.storage.guild_features(guild_id)
|
||||||
|
|
||||||
|
for feature in to_remove:
|
||||||
|
try:
|
||||||
|
features.remove(feature)
|
||||||
|
except ValueError:
|
||||||
|
raise BadRequest('Trying to remove already removed feature.')
|
||||||
|
|
||||||
|
await _update_features(guild_id, features)
|
||||||
|
return await _features(guild_id)
|
||||||
|
|
|
||||||
|
|
@ -197,12 +197,27 @@ class RelationshipType(EasyEnum):
|
||||||
|
|
||||||
|
|
||||||
class MessageNotifications(EasyEnum):
|
class MessageNotifications(EasyEnum):
|
||||||
|
"""Message notifications"""
|
||||||
ALL = 0
|
ALL = 0
|
||||||
MENTIONS = 1
|
MENTIONS = 1
|
||||||
NOTHING = 2
|
NOTHING = 2
|
||||||
|
|
||||||
|
|
||||||
class PremiumType:
|
class PremiumType:
|
||||||
|
"""Premium (Nitro) type."""
|
||||||
TIER_1 = 1
|
TIER_1 = 1
|
||||||
TIER_2 = 2
|
TIER_2 = 2
|
||||||
NONE = None
|
NONE = None
|
||||||
|
|
||||||
|
|
||||||
|
class Feature(Enum):
|
||||||
|
"""Guild features."""
|
||||||
|
invite_splash = 'INVITE_SPLASH'
|
||||||
|
vip = 'VIP_REGIONS'
|
||||||
|
vanity = 'VANITY_URL'
|
||||||
|
emoji = 'MORE_EMOJI'
|
||||||
|
verified = 'VERIFIED'
|
||||||
|
|
||||||
|
# unknown
|
||||||
|
commerce = 'COMMERCE'
|
||||||
|
news = 'NEWS'
|
||||||
|
|
|
||||||
|
|
@ -655,3 +655,10 @@ GET_MENTIONS = {
|
||||||
'everyone': {'coerce': bool, 'default': True},
|
'everyone': {'coerce': bool, 'default': True},
|
||||||
'guild_id': {'coerce': int, 'required': False}
|
'guild_id': {'coerce': int, 'required': False}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FEATURES = {
|
||||||
|
'features': {
|
||||||
|
'type': 'list', 'required': True,
|
||||||
|
'schema': {'type': 'guild_feature'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,13 @@ class Storage:
|
||||||
WHERE username = $1 AND discriminator = $2
|
WHERE username = $1 AND discriminator = $2
|
||||||
""", username, discriminator)
|
""", username, discriminator)
|
||||||
|
|
||||||
|
async def guild_features(self, guild_id: int) -> Optional[List[str]]:
|
||||||
|
"""Get a list of guild features for the given guild."""
|
||||||
|
return await self.db.fetchval("""
|
||||||
|
SELECT features FROM guilds
|
||||||
|
WHERE id = $1
|
||||||
|
""", guild_id)
|
||||||
|
|
||||||
async def get_guild(self, guild_id: int, user_id=None) -> Optional[Dict]:
|
async def get_guild(self, guild_id: int, user_id=None) -> Optional[Dict]:
|
||||||
"""Get gulid payload."""
|
"""Get gulid payload."""
|
||||||
row = await self.db.fetchrow("""
|
row = await self.db.fetchrow("""
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
# size units
|
# size units
|
||||||
KILOBYTES = 1024
|
KILOBYTES = 1024
|
||||||
|
|
||||||
|
|
@ -45,5 +47,6 @@ class Color:
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
def timestamp_(dt):
|
def timestamp_(dt) -> Optional[str]:
|
||||||
|
"""safer version for dt.isoformat()"""
|
||||||
return f'{dt.isoformat()}+00:00' if dt else None
|
return f'{dt.isoformat()}+00:00' if dt else None
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue