Skip to content
Snippets Groups Projects
Commit ef67d2ab authored by Victor Löfgren's avatar Victor Löfgren
Browse files

Resolve "Replace None with sentinel"

parent 6edbbcde
No related branches found
No related tags found
1 merge request!108Resolve "Replace None with sentinel"
Pipeline #42852 passed with warnings
Showing
with 181 additions and 143 deletions
......@@ -27,8 +27,19 @@ it('renders presentation editor', () => {
],
},
}
const typesRes: any = {
data: {
view_types: [
{
name: '',
id: 0,
},
],
},
}
;(mockedAxios.get as jest.Mock).mockImplementation((path: string, params?: any) => {
if (path.startsWith('/api/competitions')) return Promise.resolve(competitionRes)
if (path.startsWith('/api/misc/types')) return Promise.resolve(typesRes)
return Promise.resolve(citiesRes)
})
render(
......
......@@ -93,9 +93,9 @@ const PresentationEditorPage: React.FC = () => {
const competition = useAppSelector((state) => state.editor.competition)
const competitionLoading = useAppSelector((state) => state.editor.loading)
useEffect(() => {
dispatch(getTypes())
dispatch(getEditorCompetition(competitionId))
dispatch(getCities())
dispatch(getTypes())
}, [])
const setActiveSlideId = (id: number) => {
......@@ -177,7 +177,7 @@ const PresentationEditorPage: React.FC = () => {
Applicera ändringar på samtliga vyer
</Typography>
<ViewButton
activeView={activeViewTypeName === 'Audience'}
$activeView={activeViewTypeName === 'Audience'}
variant="contained"
color="secondary"
onClick={() => changeView('Audience')}
......@@ -185,7 +185,7 @@ const PresentationEditorPage: React.FC = () => {
Åskådarvy
</ViewButton>
<ViewButton
activeView={activeViewTypeName === 'Team'}
$activeView={activeViewTypeName === 'Team'}
variant="contained"
color="secondary"
onClick={() => changeView('Team')}
......
......@@ -8,12 +8,12 @@ export const ToolBarContainer = styled(Toolbar)`
`
interface ViewButtonProps {
activeView: boolean
$activeView: boolean
}
export const ViewButton = styled(Button)<ViewButtonProps>`
margin-right: 8px;
background: ${(props) => (props.activeView ? '#5a0017' : undefined)};
background: ${(props) => (props.$activeView ? '#5a0017' : undefined)};
`
export const ViewButtonClicked = styled(Button)`
......
......@@ -143,44 +143,42 @@ const OperatorViewPage: React.FC = () => {
>
<DialogTitle id="responsive-dialog-title">{'Koder för tävlingen'}</DialogTitle>
<DialogContent>
<DialogContentText>
<ListItem>
<ListItemText primary={`Domare: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
<ListItem>
<ListItemText primary={`Tävlande: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
<ListItem>
<ListItemText primary={`Publik: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
</DialogContentText>
<ListItem>
<ListItemText primary={`Domare: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
<ListItem>
<ListItemText primary={`Tävlande: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
<ListItem>
<ListItemText primary={`Publik: ${presentation.code}`} />
<Tooltip title="Kopiera kod" arrow>
<Button
onClick={() => {
navigator.clipboard.writeText(presentation.code)
}}
>
<FileCopyIcon fontSize="small" />
</Button>
</Tooltip>
</ListItem>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleClose} color="primary">
......@@ -304,11 +302,12 @@ const OperatorViewPage: React.FC = () => {
}}
>
<List>
{teams.map((team) => (
<ListItem key={team.id}>
{team.name} score: {team.question_answers}{' '}
</ListItem>
))}
{teams &&
teams.map((team) => (
<ListItem key={team.id}>
{team.name} score: {team.question_answers}{' '}
</ListItem>
))}
</List>
</Popover>
</OperatorContainer>
......
......@@ -4,14 +4,19 @@ from app.apis import item_response, list_response, protect_route
from app.core.dto import QuestionAlternativeDTO
from flask_restx import Resource
from flask_restx import reqparse
from app.core.parsers import sentinel
api = QuestionAlternativeDTO.api
schema = QuestionAlternativeDTO.schema
list_schema = QuestionAlternativeDTO.list_schema
question_alternative_parser = reqparse.RequestParser()
question_alternative_parser.add_argument("text", type=str, default=None, location="json")
question_alternative_parser.add_argument("value", type=int, default=None, location="json")
alternative_parser_add = reqparse.RequestParser()
alternative_parser_add.add_argument("text", type=str, required=True, location="json")
alternative_parser_add.add_argument("value", type=int, required=True, location="json")
alternative_parser_edit = reqparse.RequestParser()
alternative_parser_edit.add_argument("text", type=str, default=sentinel, location="json")
alternative_parser_edit.add_argument("value", type=int, default=sentinel, location="json")
@api.route("")
......@@ -24,7 +29,7 @@ class QuestionAlternativeList(Resource):
@protect_route(allowed_roles=["*"])
def post(self, competition_id, slide_id, question_id):
args = question_alternative_parser.parse_args(strict=True)
args = alternative_parser_add.parse_args(strict=True)
item = dbc.add.question_alternative(**args, question_id=question_id)
return item_response(schema.dump(item))
......@@ -39,7 +44,7 @@ class QuestionAlternatives(Resource):
@protect_route(allowed_roles=["*"])
def put(self, competition_id, slide_id, question_id, alternative_id):
args = question_alternative_parser.parse_args(strict=True)
args = alternative_parser_edit.parse_args(strict=True)
item = dbc.get.question_alternative(competition_id, slide_id, question_id, alternative_id)
item = dbc.edit.default(item, **args)
return item_response(schema.dump(item))
......
......@@ -4,19 +4,20 @@ from app.apis import item_response, list_response, protect_route
from app.core.dto import QuestionAnswerDTO
from flask_restx import Resource
from flask_restx import reqparse
from app.core.parsers import sentinel
api = QuestionAnswerDTO.api
schema = QuestionAnswerDTO.schema
list_schema = QuestionAnswerDTO.list_schema
question_answer_parser = reqparse.RequestParser()
question_answer_parser.add_argument("answer", type=str, required=True, location="json")
question_answer_parser.add_argument("score", type=int, required=True, location="json")
question_answer_parser.add_argument("question_id", type=int, required=True, location="json")
answer_parser_add = reqparse.RequestParser()
answer_parser_add.add_argument("answer", type=str, required=True, location="json")
answer_parser_add.add_argument("score", type=int, required=True, location="json")
answer_parser_add.add_argument("question_id", type=int, required=True, location="json")
question_answer_edit_parser = reqparse.RequestParser()
question_answer_edit_parser.add_argument("answer", type=str, default=None, location="json")
question_answer_edit_parser.add_argument("score", type=int, default=None, location="json")
answer_parser_edit = reqparse.RequestParser()
answer_parser_edit.add_argument("answer", type=str, default=sentinel, location="json")
answer_parser_edit.add_argument("score", type=int, default=sentinel, location="json")
@api.route("")
......@@ -29,7 +30,7 @@ class QuestionAnswerList(Resource):
@protect_route(allowed_roles=["*"], allowed_views=["*"])
def post(self, competition_id, team_id):
args = question_answer_parser.parse_args(strict=True)
args = answer_parser_add.parse_args(strict=True)
item = dbc.add.question_answer(**args, team_id=team_id)
return item_response(schema.dump(item))
......@@ -44,7 +45,7 @@ class QuestionAnswers(Resource):
@protect_route(allowed_roles=["*"], allowed_views=["*"])
def put(self, competition_id, team_id, answer_id):
args = question_answer_edit_parser.parse_args(strict=True)
args = answer_parser_edit.parse_args(strict=True)
item = dbc.get.question_answer(competition_id, team_id, answer_id)
item = dbc.edit.default(item, **args)
return item_response(schema.dump(item))
......@@ -21,14 +21,14 @@ list_schema = AuthDTO.list_schema
login_parser = reqparse.RequestParser()
login_parser.add_argument("email", type=inputs.email(), required=True, location="json")
login_parser.add_argument("password", required=True, location="json")
login_parser.add_argument("password", type=str, required=True, location="json")
create_user_parser = login_parser.copy()
create_user_parser.add_argument("city_id", type=int, required=True, location="json")
create_user_parser.add_argument("role_id", type=int, required=True, location="json")
login_code_parser = reqparse.RequestParser()
login_code_parser.add_argument("code", type=str, location="json")
login_code_parser.add_argument("code", type=str, required=True, location="json")
def get_user_claims(item_user):
......
......@@ -6,32 +6,35 @@ from app.core.dto import CompetitionDTO
from app.database.models import Competition
from flask_restx import Resource
from flask_restx import reqparse
from app.core.parsers import search_parser
from app.core.parsers import search_parser, sentinel
api = CompetitionDTO.api
schema = CompetitionDTO.schema
rich_schema = CompetitionDTO.rich_schema
list_schema = CompetitionDTO.list_schema
competition_parser = reqparse.RequestParser()
competition_parser.add_argument("name", type=str, location="json")
competition_parser.add_argument("year", type=int, location="json")
competition_parser.add_argument("city_id", type=int, location="json")
competition_parser_add = reqparse.RequestParser()
competition_parser_add.add_argument("name", type=str, required=True, location="json")
competition_parser_add.add_argument("year", type=int, required=True, location="json")
competition_parser_add.add_argument("city_id", type=int, required=True, location="json")
competition_edit_parser = competition_parser.copy()
competition_edit_parser.add_argument("background_image_id", default=None, type=int, location="json")
competition_parser_edit = reqparse.RequestParser()
competition_parser_edit.add_argument("name", type=str, default=sentinel, location="json")
competition_parser_edit.add_argument("year", type=int, default=sentinel, location="json")
competition_parser_edit.add_argument("city_id", type=int, default=sentinel, location="json")
competition_parser_edit.add_argument("background_image_id", default=sentinel, type=int, location="json")
competition_search_parser = search_parser.copy()
competition_search_parser.add_argument("name", type=str, default=None, location="args")
competition_search_parser.add_argument("year", type=int, default=None, location="args")
competition_search_parser.add_argument("city_id", type=int, default=None, location="args")
competition_parser_search = search_parser.copy()
competition_parser_search.add_argument("name", type=str, default=sentinel, location="args")
competition_parser_search.add_argument("year", type=int, default=sentinel, location="args")
competition_parser_search.add_argument("city_id", type=int, default=sentinel, location="args")
@api.route("")
class CompetitionsList(Resource):
@protect_route(allowed_roles=["*"])
def post(self):
args = competition_parser.parse_args(strict=True)
args = competition_parser_add.parse_args(strict=True)
# Add competition
item = dbc.add.competition(**args)
......@@ -52,9 +55,9 @@ class Competitions(Resource):
@protect_route(allowed_roles=["*"])
def put(self, competition_id):
args = competition_edit_parser.parse_args(strict=True)
args = competition_parser_edit.parse_args(strict=True)
item = dbc.get.one(Competition, competition_id)
item = dbc.edit.competition(item, **args)
item = dbc.edit.default(item, **args)
return item_response(schema.dump(item))
......@@ -70,7 +73,7 @@ class Competitions(Resource):
class CompetitionSearch(Resource):
@protect_route(allowed_roles=["*"])
def get(self):
args = competition_search_parser.parse_args(strict=True)
args = competition_parser_search.parse_args(strict=True)
items, total = dbc.search.competition(**args)
return list_response(list_schema.dump(items), total)
......
......@@ -4,25 +4,29 @@ from app.apis import item_response, list_response, protect_route
from app.core.dto import ComponentDTO
from flask_restx import Resource
from flask_restx import reqparse
from app.core.parsers import sentinel
api = ComponentDTO.api
schema = ComponentDTO.schema
list_schema = ComponentDTO.list_schema
component_parser_add = reqparse.RequestParser()
component_parser_add.add_argument("x", type=str, default=0, location="json")
component_parser_add.add_argument("y", type=int, default=0, location="json")
component_parser_add.add_argument("w", type=int, default=1, location="json")
component_parser_add.add_argument("h", type=int, default=1, location="json")
component_parser_add.add_argument("type_id", type=int, required=True, location="json")
component_parser_add.add_argument("view_type_id", type=int, required=True, location="json")
component_parser_add.add_argument("text", type=str, default=None, location="json")
component_parser_add.add_argument("media_id", type=str, default=None, location="json")
component_parser = reqparse.RequestParser()
component_parser.add_argument("x", type=str, default=None, location="json")
component_parser.add_argument("y", type=int, default=None, location="json")
component_parser.add_argument("w", type=int, default=None, location="json")
component_parser.add_argument("h", type=int, default=None, location="json")
component_edit_parser = component_parser.copy()
component_edit_parser.add_argument("text", type=str, location="json")
component_edit_parser.add_argument("media_id", type=str, location="json")
component_create_parser = component_edit_parser.copy()
component_create_parser.add_argument("type_id", type=int, required=True, location="json")
component_create_parser.add_argument("view_type_id", type=int, required=True, location="json")
component_parser_edit = reqparse.RequestParser()
component_parser_edit.add_argument("x", type=str, default=sentinel, location="json")
component_parser_edit.add_argument("y", type=int, default=sentinel, location="json")
component_parser_edit.add_argument("w", type=int, default=sentinel, location="json")
component_parser_edit.add_argument("h", type=int, default=sentinel, location="json")
component_parser_edit.add_argument("text", type=str, default=sentinel, location="json")
component_parser_edit.add_argument("media_id", type=str, default=sentinel, location="json")
@api.route("/<component_id>")
......@@ -35,10 +39,10 @@ class ComponentByID(Resource):
@protect_route(allowed_roles=["*"])
def put(self, competition_id, slide_id, component_id):
args = component_edit_parser.parse_args(strict=True)
args = component_parser_edit.parse_args(strict=True)
item = dbc.get.component(competition_id, slide_id, component_id)
args_without_none = {key: value for key, value in args.items() if value is not None}
item = dbc.edit.default(item, **args_without_none)
args_without_sentinel = {key: value for key, value in args.items() if value is not sentinel}
item = dbc.edit.default(item, **args_without_sentinel)
return item_response(schema.dump(item))
@protect_route(allowed_roles=["*"])
......@@ -58,6 +62,6 @@ class ComponentList(Resource):
@protect_route(allowed_roles=["*"])
def post(self, competition_id, slide_id):
args = component_create_parser.parse_args()
args = component_parser_add.parse_args()
item = dbc.add.component(slide_id=slide_id, **args)
return item_response(schema.dump(item))
......@@ -10,6 +10,7 @@ from flask_restx import Resource
from flask_uploads import UploadNotAllowed
from sqlalchemy import exc
import app.core.files as files
from app.core.parsers import sentinel
api = MediaDTO.api
image_set = MediaDTO.image_set
......@@ -17,7 +18,7 @@ schema = MediaDTO.schema
list_schema = MediaDTO.list_schema
media_parser_search = search_parser.copy()
media_parser_search.add_argument("filename", type=str, default=None, location="args")
media_parser_search.add_argument("filename", type=str, default=sentinel, location="args")
@api.route("/images")
......
......@@ -4,15 +4,21 @@ from app.apis import item_response, list_response, protect_route
from app.core.dto import QuestionDTO
from flask_restx import Resource
from flask_restx import reqparse
from app.core.parsers import sentinel
api = QuestionDTO.api
schema = QuestionDTO.schema
list_schema = QuestionDTO.list_schema
question_parser = reqparse.RequestParser()
question_parser.add_argument("name", type=str, default=None, location="json")
question_parser.add_argument("total_score", type=int, default=None, location="json")
question_parser.add_argument("type_id", type=int, default=None, location="json")
question_parser_add = reqparse.RequestParser()
question_parser_add.add_argument("name", type=str, default=None, location="json")
question_parser_add.add_argument("total_score", type=int, default=None, location="json")
question_parser_add.add_argument("type_id", type=int, required=True, location="json")
question_parser_edit = reqparse.RequestParser()
question_parser_edit.add_argument("name", type=str, default=sentinel, location="json")
question_parser_edit.add_argument("total_score", type=int, default=sentinel, location="json")
question_parser_edit.add_argument("type_id", type=int, default=sentinel, location="json")
@api.route("/questions")
......@@ -34,7 +40,7 @@ class QuestionListForSlide(Resource):
@protect_route(allowed_roles=["*"])
def post(self, competition_id, slide_id):
args = question_parser.parse_args(strict=True)
args = question_parser_add.parse_args(strict=True)
item = dbc.add.question(slide_id=slide_id, **args)
return item_response(schema.dump(item))
......@@ -49,7 +55,7 @@ class QuestionById(Resource):
@protect_route(allowed_roles=["*"])
def put(self, competition_id, slide_id, question_id):
args = question_parser.parse_args(strict=True)
args = question_parser_edit.parse_args(strict=True)
item_question = dbc.get.question(competition_id, slide_id, question_id)
item_question = dbc.edit.default(item_question, **args)
......
......@@ -4,16 +4,17 @@ from app.apis import item_response, list_response, protect_route
from app.core.dto import SlideDTO
from flask_restx import Resource
from flask_restx import reqparse
from app.core.parsers import sentinel
api = SlideDTO.api
schema = SlideDTO.schema
list_schema = SlideDTO.list_schema
slide_parser = reqparse.RequestParser()
slide_parser.add_argument("order", type=int, default=None, location="json")
slide_parser.add_argument("title", type=str, default=None, location="json")
slide_parser.add_argument("timer", type=int, default=None, location="json")
slide_parser.add_argument("background_image_id", default=None, type=int, location="json")
slide_parser_edit = reqparse.RequestParser()
slide_parser_edit.add_argument("order", type=int, default=sentinel, location="json")
slide_parser_edit.add_argument("title", type=str, default=sentinel, location="json")
slide_parser_edit.add_argument("timer", type=int, default=sentinel, location="json")
slide_parser_edit.add_argument("background_image_id", default=sentinel, type=int, location="json")
@api.route("")
......@@ -40,10 +41,10 @@ class Slides(Resource):
@protect_route(allowed_roles=["*"])
def put(self, competition_id, slide_id):
args = slide_parser.parse_args(strict=True)
args = slide_parser_edit.parse_args(strict=True)
item_slide = dbc.get.slide(competition_id, slide_id)
item_slide = dbc.edit.slide(item_slide, **args)
item_slide = dbc.edit.default(item_slide, **args)
return item_response(schema.dump(item_slide))
......@@ -60,7 +61,7 @@ class Slides(Resource):
class SlideOrder(Resource):
@protect_route(allowed_roles=["*"])
def put(self, competition_id, slide_id):
args = slide_parser.parse_args(strict=True)
args = slide_parser_edit.parse_args(strict=True)
order = args.get("order")
item_slide = dbc.get.slide(competition_id, slide_id)
......
......@@ -3,14 +3,17 @@ import app.database.controller as dbc
from app.apis import item_response, list_response, protect_route
from app.core.dto import TeamDTO
from flask_restx import Resource, reqparse
from flask_restx import reqparse
from app.core.parsers import sentinel
api = TeamDTO.api
schema = TeamDTO.schema
list_schema = TeamDTO.list_schema
team_parser = reqparse.RequestParser()
team_parser.add_argument("name", type=str, location="json")
team_parser_add = reqparse.RequestParser()
team_parser_add.add_argument("name", type=str, required=True, location="json")
team_parser_edit = reqparse.RequestParser()
team_parser_edit.add_argument("name", type=str, default=sentinel, location="json")
@api.route("")
......@@ -23,7 +26,7 @@ class TeamsList(Resource):
@protect_route(allowed_roles=["*"])
def post(self, competition_id):
args = team_parser.parse_args(strict=True)
args = team_parser_add.parse_args(strict=True)
item_team = dbc.add.team(args["name"], competition_id)
return item_response(schema.dump(item_team))
......@@ -45,7 +48,7 @@ class Teams(Resource):
@protect_route(allowed_roles=["*"])
def put(self, competition_id, team_id):
args = team_parser.parse_args(strict=True)
args = team_parser_edit.parse_args(strict=True)
name = args.get("name")
item_team = dbc.get.team(competition_id, team_id)
......
......@@ -5,23 +5,23 @@ from app.core.dto import UserDTO
from flask_jwt_extended import get_jwt_identity
from flask_restx import Resource
from flask_restx import inputs, reqparse
from app.core.parsers import search_parser
from app.core.parsers import search_parser, sentinel
api = UserDTO.api
schema = UserDTO.schema
list_schema = UserDTO.list_schema
user_parser = reqparse.RequestParser()
user_parser.add_argument("email", type=inputs.email(), location="json")
user_parser.add_argument("name", type=str, location="json")
user_parser.add_argument("city_id", type=int, location="json")
user_parser.add_argument("role_id", type=int, location="json")
user_parser_edit = reqparse.RequestParser()
user_parser_edit.add_argument("email", type=inputs.email(), default=sentinel, location="json")
user_parser_edit.add_argument("name", type=str, default=sentinel, location="json")
user_parser_edit.add_argument("city_id", type=int, default=sentinel, location="json")
user_parser_edit.add_argument("role_id", type=int, default=sentinel, location="json")
user_search_parser = search_parser.copy()
user_search_parser.add_argument("name", type=str, default=None, location="args")
user_search_parser.add_argument("email", type=str, default=None, location="args")
user_search_parser.add_argument("city_id", type=int, default=None, location="args")
user_search_parser.add_argument("role_id", type=int, default=None, location="args")
user_search_parser.add_argument("name", type=str, default=sentinel, location="args")
user_search_parser.add_argument("email", type=str, default=sentinel, location="args")
user_search_parser.add_argument("city_id", type=int, default=sentinel, location="args")
user_search_parser.add_argument("role_id", type=int, default=sentinel, location="args")
def _edit_user(item_user, args):
......@@ -47,7 +47,7 @@ class UsersList(Resource):
@protect_route(allowed_roles=["*"])
def put(self):
args = user_parser.parse_args(strict=True)
args = user_parser_edit.parse_args(strict=True)
item = dbc.get.user(get_jwt_identity())
item = _edit_user(item, args)
return item_response(schema.dump(item))
......@@ -63,7 +63,7 @@ class Users(Resource):
@protect_route(allowed_roles=["Admin"])
def put(self, ID):
args = user_parser.parse_args(strict=True)
args = user_parser_edit.parse_args(strict=True)
item = dbc.get.user(ID)
item = _edit_user(item, args)
return item_response(schema.dump(item))
......
from flask_restx import inputs, reqparse
class Sentinel:
"""
Sentinel is used as default argument to parsers if it isn't necessary to
supply a value. This is used instead of None so that None can be supplied
as value.
"""
def __repr__(self):
return "Sentinel"
def __bool__(self):
return False
sentinel = Sentinel()
###SEARCH####
search_parser = reqparse.RequestParser()
search_parser.add_argument("page", type=int, default=0, location="args")
......
......@@ -3,6 +3,7 @@ This file contains functionality to get data from the database.
"""
from app.core import db
from app.core.parsers import sentinel
def switch_order(item1, item2):
......@@ -46,22 +47,8 @@ def default(item, **kwargs):
for key, value in kwargs.items():
if not hasattr(item, key):
raise AttributeError(f"Item of type {type(item)} has no attribute '{key}'")
if value is not None:
if value is not sentinel:
setattr(item, key, value)
db.session.commit()
db.session.refresh(item)
return item
def competition(item, **kwargs):
if kwargs["background_image_id"] == -1:
item.background_image_id = None
del kwargs["background_image_id"]
return default(item, **kwargs)
def slide(item, **kwargs):
if kwargs["background_image_id"] == -1:
item.background_image_id = None
del kwargs["background_image_id"]
return default(item, **kwargs)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment