Wish requesters
This commit is contained in:
parent
ad24506ab7
commit
64a9e063ec
@ -55,6 +55,9 @@
|
|||||||
- Allow for advanced migration scenarios through companion python files
|
- Allow for advanced migration scenarios through companion python files
|
||||||
- Add a bunch of the requested fields into the database for future implementation
|
- Add a bunch of the requested fields into the database for future implementation
|
||||||
|
|
||||||
|
- Wish
|
||||||
|
- Requester
|
||||||
|
|
||||||
### UI
|
### UI
|
||||||
|
|
||||||
- Add
|
- Add
|
||||||
@ -101,6 +104,9 @@
|
|||||||
- Storage list
|
- Storage list
|
||||||
- Storage content
|
- Storage content
|
||||||
|
|
||||||
|
- Wish
|
||||||
|
- Requester
|
||||||
|
|
||||||
## 1.1.1: PDF Instructions Download
|
## 1.1.1: PDF Instructions Download
|
||||||
|
|
||||||
### Instructions
|
### Instructions
|
||||||
|
@ -11,6 +11,7 @@ from .set_purchase_location import BrickSetPurchaseLocation
|
|||||||
from .set_status import BrickSetStatus
|
from .set_status import BrickSetStatus
|
||||||
from .set_storage import BrickSetStorage
|
from .set_storage import BrickSetStorage
|
||||||
from .set_tag import BrickSetTag
|
from .set_tag import BrickSetTag
|
||||||
|
from .wish_owner import BrickWishOwner
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -20,7 +21,8 @@ T = TypeVar(
|
|||||||
BrickSetPurchaseLocation,
|
BrickSetPurchaseLocation,
|
||||||
BrickSetStatus,
|
BrickSetStatus,
|
||||||
BrickSetStorage,
|
BrickSetStorage,
|
||||||
BrickSetTag
|
BrickSetTag,
|
||||||
|
BrickWishOwner
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ if TYPE_CHECKING:
|
|||||||
from .set_storage import BrickSetStorage
|
from .set_storage import BrickSetStorage
|
||||||
from .set_tag import BrickSetTag
|
from .set_tag import BrickSetTag
|
||||||
from .wish import BrickWish
|
from .wish import BrickWish
|
||||||
|
from .wish_owner import BrickWishOwner
|
||||||
|
|
||||||
T = TypeVar(
|
T = TypeVar(
|
||||||
'T',
|
'T',
|
||||||
@ -26,6 +27,7 @@ T = TypeVar(
|
|||||||
'BrickSetStorage',
|
'BrickSetStorage',
|
||||||
'BrickSetTag',
|
'BrickSetTag',
|
||||||
'BrickWish',
|
'BrickWish',
|
||||||
|
'BrickWishOwner',
|
||||||
'RebrickableSet'
|
'RebrickableSet'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ from .set_status_list import BrickSetStatusList
|
|||||||
from .set_storage_list import BrickSetStorageList
|
from .set_storage_list import BrickSetStorageList
|
||||||
from .set_tag_list import BrickSetTagList
|
from .set_tag_list import BrickSetTagList
|
||||||
from .theme_list import BrickThemeList
|
from .theme_list import BrickThemeList
|
||||||
|
from .wish_owner_list import BrickWishOwnerList
|
||||||
|
|
||||||
|
|
||||||
# Reload everything related to a database after an operation
|
# Reload everything related to a database after an operation
|
||||||
@ -35,5 +36,8 @@ def reload() -> None:
|
|||||||
|
|
||||||
# Reload themes
|
# Reload themes
|
||||||
BrickThemeList(force=True)
|
BrickThemeList(force=True)
|
||||||
|
|
||||||
|
# Reload the wish owners
|
||||||
|
BrickWishOwnerList.new(force=True)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
@ -16,4 +16,11 @@ CREATE TABLE "bricktracker_set_owners" (
|
|||||||
FOREIGN KEY("id") REFERENCES "bricktracker_sets"("id")
|
FOREIGN KEY("id") REFERENCES "bricktracker_sets"("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Create a table for the wish owners
|
||||||
|
CREATE TABLE "bricktracker_wish_owners" (
|
||||||
|
"set" TEXT NOT NULL,
|
||||||
|
PRIMARY KEY("set"),
|
||||||
|
FOREIGN KEY("set") REFERENCES "bricktracker_wishes"("set")
|
||||||
|
);
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
@ -3,6 +3,10 @@ BEGIN TRANSACTION;
|
|||||||
ALTER TABLE "bricktracker_set_owners"
|
ALTER TABLE "bricktracker_set_owners"
|
||||||
DROP COLUMN "owner_{{ id }}";
|
DROP COLUMN "owner_{{ id }}";
|
||||||
|
|
||||||
|
-- Also drop from wishes
|
||||||
|
ALTER TABLE "bricktracker_wish_owners"
|
||||||
|
DROP COLUMN "owner_{{ id }}";
|
||||||
|
|
||||||
DELETE FROM "bricktracker_metadata_owners"
|
DELETE FROM "bricktracker_metadata_owners"
|
||||||
WHERE "bricktracker_metadata_owners"."id" IS NOT DISTINCT FROM '{{ id }}';
|
WHERE "bricktracker_metadata_owners"."id" IS NOT DISTINCT FROM '{{ id }}';
|
||||||
|
|
||||||
|
@ -3,6 +3,10 @@ BEGIN TRANSACTION;
|
|||||||
ALTER TABLE "bricktracker_set_owners"
|
ALTER TABLE "bricktracker_set_owners"
|
||||||
ADD COLUMN "owner_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
ADD COLUMN "owner_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
|
-- Also inject into wishes
|
||||||
|
ALTER TABLE "bricktracker_wish_owners"
|
||||||
|
ADD COLUMN "owner_{{ id }}" BOOLEAN NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
INSERT INTO "bricktracker_metadata_owners" (
|
INSERT INTO "bricktracker_metadata_owners" (
|
||||||
"id",
|
"id",
|
||||||
"name"
|
"name"
|
||||||
|
@ -5,9 +5,17 @@ SELECT
|
|||||||
"bricktracker_wishes"."theme_id",
|
"bricktracker_wishes"."theme_id",
|
||||||
"bricktracker_wishes"."number_of_parts",
|
"bricktracker_wishes"."number_of_parts",
|
||||||
"bricktracker_wishes"."image",
|
"bricktracker_wishes"."image",
|
||||||
|
{% block owners %}
|
||||||
|
{% if owners %}{{ owners }},{% endif %}
|
||||||
|
{% endblock %}
|
||||||
"bricktracker_wishes"."url"
|
"bricktracker_wishes"."url"
|
||||||
FROM "bricktracker_wishes"
|
FROM "bricktracker_wishes"
|
||||||
|
|
||||||
|
{% if owners %}
|
||||||
|
LEFT JOIN "bricktracker_wish_owners"
|
||||||
|
ON "bricktracker_wishes"."set" IS NOT DISTINCT FROM "bricktracker_wish_owners"."set"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% block where %}{% endblock %}
|
{% block where %}{% endblock %}
|
||||||
|
|
||||||
{% if order %}
|
{% if order %}
|
||||||
|
@ -1,2 +1,12 @@
|
|||||||
|
-- A bit unsafe as it does not use a prepared statement but it
|
||||||
|
-- should not be possible to inject anything through the {{ set }} context
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
DELETE FROM "bricktracker_wishes"
|
DELETE FROM "bricktracker_wishes"
|
||||||
WHERE "bricktracker_wishes"."set" IS NOT DISTINCT FROM :set
|
WHERE "bricktracker_wishes"."set" IS NOT DISTINCT FROM '{{ set }}';
|
||||||
|
|
||||||
|
DELETE FROM "bricktracker_wish_owners"
|
||||||
|
WHERE "bricktracker_wish_owners"."set" IS NOT DISTINCT FROM '{{ set }}';
|
||||||
|
|
||||||
|
COMMIT;
|
10
bricktracker/sql/wish/metadata/owner/update/state.sql
Normal file
10
bricktracker/sql/wish/metadata/owner/update/state.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
INSERT INTO "bricktracker_wish_owners" (
|
||||||
|
"set",
|
||||||
|
"{{name}}"
|
||||||
|
) VALUES (
|
||||||
|
:set,
|
||||||
|
:state
|
||||||
|
)
|
||||||
|
ON CONFLICT("set")
|
||||||
|
DO UPDATE SET "{{name}}" = :state
|
||||||
|
WHERE "bricktracker_wish_owners"."set" IS NOT DISTINCT FROM :set
|
@ -1,4 +1,11 @@
|
|||||||
from flask import Blueprint, redirect, render_template, request, url_for
|
from flask import (
|
||||||
|
Blueprint,
|
||||||
|
jsonify,
|
||||||
|
redirect,
|
||||||
|
render_template,
|
||||||
|
request,
|
||||||
|
url_for
|
||||||
|
)
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
from werkzeug.wrappers.response import Response
|
from werkzeug.wrappers.response import Response
|
||||||
|
|
||||||
@ -6,8 +13,10 @@ from .exceptions import exception_handler
|
|||||||
from ..retired_list import BrickRetiredList
|
from ..retired_list import BrickRetiredList
|
||||||
from ..wish import BrickWish
|
from ..wish import BrickWish
|
||||||
from ..wish_list import BrickWishList
|
from ..wish_list import BrickWishList
|
||||||
|
from ..wish_owner_list import BrickWishOwnerList
|
||||||
|
|
||||||
wish_page = Blueprint('wish', __name__, url_prefix='/wishlist')
|
|
||||||
|
wish_page = Blueprint('wish', __name__, url_prefix='/wishes')
|
||||||
|
|
||||||
|
|
||||||
# Index
|
# Index
|
||||||
@ -18,7 +27,8 @@ def list() -> str:
|
|||||||
'wishes.html',
|
'wishes.html',
|
||||||
table_collection=BrickWishList().all(),
|
table_collection=BrickWishList().all(),
|
||||||
retired=BrickRetiredList(),
|
retired=BrickRetiredList(),
|
||||||
error=request.args.get('error')
|
error=request.args.get('error'),
|
||||||
|
owners=BrickWishOwnerList.list(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -27,21 +37,60 @@ def list() -> str:
|
|||||||
@login_required
|
@login_required
|
||||||
@exception_handler(__file__, post_redirect='wish.list')
|
@exception_handler(__file__, post_redirect='wish.list')
|
||||||
def add() -> Response:
|
def add() -> Response:
|
||||||
# Grab the set number
|
# Grab the set
|
||||||
number: str = request.form.get('number', '')
|
set: str = request.form.get('set', '')
|
||||||
|
|
||||||
if number != '':
|
if set != '':
|
||||||
BrickWishList.add(number)
|
BrickWishList.add(set)
|
||||||
|
|
||||||
return redirect(url_for('wish.list'))
|
return redirect(url_for('wish.list'))
|
||||||
|
|
||||||
|
|
||||||
# Delete a set from the wishlit
|
# Ask for deletion of a wish
|
||||||
@wish_page.route('/delete/<number>', methods=['POST'])
|
@wish_page.route('/<set>/delete', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
@exception_handler(__file__)
|
||||||
|
def delete(*, set: str) -> str:
|
||||||
|
return render_template(
|
||||||
|
'wish.html',
|
||||||
|
delete=True,
|
||||||
|
item=BrickWish().select_specific(set),
|
||||||
|
error=request.args.get('error'),
|
||||||
|
owners=BrickWishOwnerList.list(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Actually delete of a set
|
||||||
|
@wish_page.route('/<set>/delete', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@exception_handler(__file__, post_redirect='wish.list')
|
@exception_handler(__file__, post_redirect='wish.list')
|
||||||
def delete(*, number: str) -> Response:
|
def do_delete(*, set: str) -> Response:
|
||||||
brickwish = BrickWish().select_specific(number)
|
brickwish = BrickWish().select_specific(set)
|
||||||
brickwish.delete()
|
brickwish.delete()
|
||||||
|
|
||||||
return redirect(url_for('wish.list'))
|
return redirect(url_for('wish.list'))
|
||||||
|
|
||||||
|
|
||||||
|
# Details
|
||||||
|
@wish_page.route('/<set>/details', methods=['GET'])
|
||||||
|
@exception_handler(__file__)
|
||||||
|
def details(*, set: str) -> str:
|
||||||
|
return render_template(
|
||||||
|
'wish.html',
|
||||||
|
item=BrickWish().select_specific(set),
|
||||||
|
retired=BrickRetiredList(),
|
||||||
|
owners=BrickWishOwnerList.list(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Change the state of a owner
|
||||||
|
@wish_page.route('/<set>/owner/<metadata_id>', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@exception_handler(__file__, json=True)
|
||||||
|
def update_owner(*, set: str, metadata_id: str) -> Response:
|
||||||
|
brickwish = BrickWish().select_specific(set)
|
||||||
|
owner = BrickWishOwnerList.get(metadata_id)
|
||||||
|
|
||||||
|
state = owner.update_wish_state(brickwish, json=request.json)
|
||||||
|
|
||||||
|
return jsonify({'value': state})
|
||||||
|
@ -5,6 +5,7 @@ from flask import url_for
|
|||||||
from .exceptions import NotFoundException
|
from .exceptions import NotFoundException
|
||||||
from .rebrickable_set import RebrickableSet
|
from .rebrickable_set import RebrickableSet
|
||||||
from .sql import BrickSQL
|
from .sql import BrickSQL
|
||||||
|
from .wish_owner_list import BrickWishOwnerList
|
||||||
|
|
||||||
|
|
||||||
# Lego brick wished set
|
# Lego brick wished set
|
||||||
@ -16,11 +17,11 @@ class BrickWish(RebrickableSet):
|
|||||||
select_query: str = 'wish/select'
|
select_query: str = 'wish/select'
|
||||||
insert_query: str = 'wish/insert'
|
insert_query: str = 'wish/insert'
|
||||||
|
|
||||||
# Delete a wished set
|
# Delete a wish
|
||||||
def delete(self, /) -> None:
|
def delete(self, /) -> None:
|
||||||
BrickSQL().execute_and_commit(
|
BrickSQL().executescript(
|
||||||
'wish/delete/wish',
|
'wish/delete/wish',
|
||||||
parameters=self.sql_parameters()
|
set=self.fields.set
|
||||||
)
|
)
|
||||||
|
|
||||||
# Select a specific part (with a set and an id)
|
# Select a specific part (with a set and an id)
|
||||||
@ -29,7 +30,7 @@ class BrickWish(RebrickableSet):
|
|||||||
self.fields.set = set
|
self.fields.set = set
|
||||||
|
|
||||||
# Load from database
|
# Load from database
|
||||||
if not self.select():
|
if not self.select(owners=BrickWishOwnerList.as_columns()):
|
||||||
raise NotFoundException(
|
raise NotFoundException(
|
||||||
'Wish for set {set} was not found in the database'.format( # noqa: E501
|
'Wish for set {set} was not found in the database'.format( # noqa: E501
|
||||||
set=self.fields.set,
|
set=self.fields.set,
|
||||||
@ -38,6 +39,14 @@ class BrickWish(RebrickableSet):
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
# Self url
|
||||||
|
def url(self, /) -> str:
|
||||||
|
return url_for('wish.details', set=self.fields.set)
|
||||||
|
|
||||||
# Deletion url
|
# Deletion url
|
||||||
def url_for_delete(self, /) -> str:
|
def url_for_delete(self, /) -> str:
|
||||||
return url_for('wish.delete', number=self.fields.set)
|
return url_for('wish.delete', set=self.fields.set)
|
||||||
|
|
||||||
|
# Actual deletion url
|
||||||
|
def url_for_do_delete(self, /) -> str:
|
||||||
|
return url_for('wish.do_delete', set=self.fields.set)
|
||||||
|
@ -9,6 +9,7 @@ from .rebrickable import Rebrickable
|
|||||||
from .rebrickable_image import RebrickableImage
|
from .rebrickable_image import RebrickableImage
|
||||||
from .record_list import BrickRecordList
|
from .record_list import BrickRecordList
|
||||||
from .wish import BrickWish
|
from .wish import BrickWish
|
||||||
|
from .wish_owner_list import BrickWishOwnerList
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -22,7 +23,8 @@ class BrickWishList(BrickRecordList[BrickWish]):
|
|||||||
def all(self, /) -> Self:
|
def all(self, /) -> Self:
|
||||||
# Load the wished sets from the database
|
# Load the wished sets from the database
|
||||||
for record in self.select(
|
for record in self.select(
|
||||||
order=current_app.config['WISHES_DEFAULT_ORDER']
|
order=current_app.config['WISHES_DEFAULT_ORDER'],
|
||||||
|
owners=BrickWishOwnerList.as_columns(),
|
||||||
):
|
):
|
||||||
brickwish = BrickWish(record=record)
|
brickwish = BrickWish(record=record)
|
||||||
|
|
||||||
|
70
bricktracker/wish_owner.py
Normal file
70
bricktracker/wish_owner.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
|
from flask import url_for
|
||||||
|
|
||||||
|
from .exceptions import DatabaseException
|
||||||
|
from .metadata import BrickMetadata
|
||||||
|
from .sql import BrickSQL
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .wish import BrickWish
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# Lego wish owner metadata
|
||||||
|
class BrickWishOwner(BrickMetadata):
|
||||||
|
kind: str = 'owner'
|
||||||
|
|
||||||
|
# Wish state endpoint
|
||||||
|
wish_state_endpoint: str = 'wish.update_owner'
|
||||||
|
|
||||||
|
# Queries
|
||||||
|
update_wish_state_query: str = 'wish/metadata/owner/update/state'
|
||||||
|
|
||||||
|
# Update the selected state of this metadata item for a wish
|
||||||
|
def update_wish_state(
|
||||||
|
self,
|
||||||
|
brickset: 'BrickWish',
|
||||||
|
/,
|
||||||
|
*,
|
||||||
|
json: Any | None = None,
|
||||||
|
state: Any | None = None
|
||||||
|
) -> Any:
|
||||||
|
if state is None and json is not None:
|
||||||
|
state = json.get('value', False)
|
||||||
|
|
||||||
|
parameters = self.sql_parameters()
|
||||||
|
parameters['set'] = brickset.fields.set
|
||||||
|
parameters['state'] = state
|
||||||
|
|
||||||
|
rows, _ = BrickSQL().execute_and_commit(
|
||||||
|
self.update_wish_state_query,
|
||||||
|
parameters=parameters,
|
||||||
|
name=self.as_column(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if rows != 1:
|
||||||
|
raise DatabaseException('Could not update the {kind} "{name}" state for wish {set}'.format( # noqa: E501
|
||||||
|
kind=self.kind,
|
||||||
|
name=self.fields.name,
|
||||||
|
set=brickset.fields.set,
|
||||||
|
))
|
||||||
|
|
||||||
|
# Info
|
||||||
|
logger.info('{kind} "{name}" state changed to "{state}" for wish {set}'.format( # noqa: E501
|
||||||
|
kind=self.kind,
|
||||||
|
name=self.fields.name,
|
||||||
|
state=state,
|
||||||
|
set=brickset.fields.set,
|
||||||
|
))
|
||||||
|
|
||||||
|
return state
|
||||||
|
|
||||||
|
# URL to change the selected state of this metadata item for a wish
|
||||||
|
def url_for_wish_state(self, set: str, /) -> str:
|
||||||
|
return url_for(
|
||||||
|
self.wish_state_endpoint,
|
||||||
|
set=set,
|
||||||
|
metadata_id=self.fields.id
|
||||||
|
)
|
21
bricktracker/wish_owner_list.py
Normal file
21
bricktracker/wish_owner_list.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from typing import Self
|
||||||
|
|
||||||
|
from .metadata_list import BrickMetadataList
|
||||||
|
from .wish_owner import BrickWishOwner
|
||||||
|
|
||||||
|
|
||||||
|
# Lego sets owner list
|
||||||
|
class BrickWishOwnerList(BrickMetadataList[BrickWishOwner]):
|
||||||
|
kind: str = 'wish owners'
|
||||||
|
|
||||||
|
# Database
|
||||||
|
table: str = 'bricktracker_wish_owners'
|
||||||
|
order: str = '"bricktracker_metadata_owners"."name"'
|
||||||
|
|
||||||
|
# Queries
|
||||||
|
select_query = 'set/metadata/owner/list'
|
||||||
|
|
||||||
|
# Instantiate the list with the proper class
|
||||||
|
@classmethod
|
||||||
|
def new(cls, /, *, force: bool = False) -> Self:
|
||||||
|
return cls(BrickWishOwner, force=force)
|
15
templates/wish.html
Normal file
15
templates/wish.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %} - {% if delete %}Delete a wish{% else %}Wish{% endif %} {{ item.fields.name}} ({{ item.fields.set }}){% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
{% with solo=true, delete=delete %}
|
||||||
|
{% include 'wish/card.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
49
templates/wish/card.html
Normal file
49
templates/wish/card.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{% import 'macro/accordion.html' as accordion %}
|
||||||
|
{% import 'macro/badge.html' as badge %}
|
||||||
|
{% import 'macro/card.html' as card %}
|
||||||
|
{% import 'macro/form.html' as form %}
|
||||||
|
|
||||||
|
<div class="card mb-3 flex-fill {% if solo %}card-solo{% endif %}">
|
||||||
|
{{ card.header(item, item.fields.name, solo=solo, identifier=item.fields.set) }}
|
||||||
|
{{ card.image(item, solo=solo, last=last, caption=item.fields.name, alt=item.fields.set) }}
|
||||||
|
<div class="card-body border-bottom-0 {% if not solo %}p-1{% endif %}">
|
||||||
|
{{ badge.theme(item.theme.name, solo=solo, last=last) }}
|
||||||
|
{{ badge.parts(item.fields.number_of_parts, solo=solo, last=last) }}
|
||||||
|
{% for owner in owners %}
|
||||||
|
{{ badge.owner(item, owner, solo=solo, last=last) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% if solo and g.login.is_authenticated() %}
|
||||||
|
<div class="accordion accordion-flush border-top" id="wish-details">
|
||||||
|
{% if not delete %}
|
||||||
|
{{ accordion.header('Requester', 'owner', 'wish-details', icon='group-line', class='p-0') }}
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
{% if owners | length %}
|
||||||
|
{% for owner in owners %}
|
||||||
|
<li class="d-flex list-group-item list-group-item-action text-nowrap">{{ form.checkbox(owner.fields.name, item.fields.set, owner.as_dataset(), owner.url_for_wish_state(item.fields.set), item.fields[owner.as_column()], delete=delete) }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<li class="list-group-item list-group-item-action text-center"><i class="ri-error-warning-line"></i> No requester found.</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
<div class="list-group list-group-flush border-top">
|
||||||
|
<a class="list-group-item list-group-item-action" href="{{ url_for('admin.admin', open_owner=true) }}"><i class="ri-settings-4-line"></i> Manage the set owners</a>
|
||||||
|
</div>
|
||||||
|
{{ accordion.footer() }}
|
||||||
|
{% endif %}
|
||||||
|
{{ accordion.header('Danger zone', 'danger-zone', 'wish-details', expanded=delete, danger=true, class='text-end') }}
|
||||||
|
{% if delete %}
|
||||||
|
<form action="{{ item.url_for_do_delete() }}" method="post">
|
||||||
|
{% if error %}<div class="alert alert-danger text-start" role="alert"><strong>Error:</strong> {{ error }}.</div>{% endif %}
|
||||||
|
<div class="alert alert-danger text-center" role="alert">You are about to delete a wish. This action is irreversible.</div>
|
||||||
|
<a class="btn btn-primary" href="{{ item.url() }}" role="button"><i class="ri-arrow-left-long-line"></i> Back to the wish</a>
|
||||||
|
<button type="submit" class="btn btn-danger"><i class="ri-close-line"></i> Delete the wish</button>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ item.url_for_delete() }}" class="btn btn-danger" role="button"><i class="ri-close-line"></i> Delete the wish</a>
|
||||||
|
{% endif %}
|
||||||
|
{{ accordion.footer() }}
|
||||||
|
</div>
|
||||||
|
<div class="card-footer"></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
@ -12,6 +12,7 @@
|
|||||||
<th scope="col"><i class="ri-calendar-line fw-normal"></i> Year</th>
|
<th scope="col"><i class="ri-calendar-line fw-normal"></i> Year</th>
|
||||||
<th scope="col"><i class="ri-shapes-line fw-normal"></i> Parts</th>
|
<th scope="col"><i class="ri-shapes-line fw-normal"></i> Parts</th>
|
||||||
<th scope="col"><i class="ri-calendar-close-line fw-normal"></i> Retirement</th>
|
<th scope="col"><i class="ri-calendar-close-line fw-normal"></i> Retirement</th>
|
||||||
|
<th data-table-no-sort="true" class="no-sort" scope="col"><i class="ri-user-line fw-normal"></i> Requesters</th>
|
||||||
{% if g.login.is_authenticated() %}
|
{% if g.login.is_authenticated() %}
|
||||||
<th data-table-no-sort-and-search="true" class="no-sort" scope="col"><i class="ri-settings-4-line fw-normal"></i> Actions</th>
|
<th data-table-no-sort-and-search="true" class="no-sort" scope="col"><i class="ri-settings-4-line fw-normal"></i> Actions</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -28,11 +29,15 @@
|
|||||||
<td>{{ item.fields.year }}</td>
|
<td>{{ item.fields.year }}</td>
|
||||||
<td>{{ item.fields.number_of_parts }}</td>
|
<td>{{ item.fields.number_of_parts }}</td>
|
||||||
<td>{% if retirement_date %}{{ retirement_date }}{% else %}<span class="badge rounded-pill text-bg-light border">Not found</span>{% endif %}</td>
|
<td>{% if retirement_date %}{{ retirement_date }}{% else %}<span class="badge rounded-pill text-bg-light border">Not found</span>{% endif %}</td>
|
||||||
|
<td>
|
||||||
|
{% for owner in owners %}
|
||||||
|
{{ badge.owner(item, owner) }}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
{% if g.login.is_authenticated() %}
|
{% if g.login.is_authenticated() %}
|
||||||
<td>
|
<td>
|
||||||
<form action="{{ item.url_for_delete() }}" method="post">
|
<a href="{{ item.url() }}" class="btn btn-sm btn-primary mb-1" role="button"><i class="ri-gift-line"></i> Details</a>
|
||||||
<button type="submit" class="btn btn-sm btn-danger"><i class="ri-delete-bin-2-line"></i> Delete</button>
|
<a href="{{ item.url_for_delete() }}" class="btn btn-sm btn-danger mb-1" role="button"><i class="ri-delete-bin-2-line"></i> Delete</a>
|
||||||
</form>
|
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<label class="visually-hidden" for="number">Set number</label>
|
<label class="visually-hidden" for="number">Set number</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-text"><i class="ri-hashtag"></i></div>
|
<div class="input-group-text"><i class="ri-hashtag"></i></div>
|
||||||
<input type="text" class="form-control" id="number" name="number" placeholder="107-1 or 1642-1 or ..." value="" autocomplete="off">
|
<input type="text" class="form-control" id="set" name="set" placeholder="107-1 or 1642-1 or ..." value="" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
Loading…
Reference in New Issue
Block a user