Compare commits
8 Commits
00b1d4ee8d
...
6e4dd4bf96
Author | SHA1 | Date |
---|---|---|
Lukáš Kucharczyk | 6e4dd4bf96 | |
Lukáš Kucharczyk | 7a6a56a589 | |
Lukáš Kucharczyk | 63c70d4b31 | |
Lukáš Kucharczyk | e9e61403a9 | |
Lukáš Kucharczyk | 6ac4209492 | |
Lukáš Kucharczyk | f0ac07dc6d | |
Lukáš Kucharczyk | d947c6efe1 | |
Lukáš Kucharczyk | 600c0d284c |
|
@ -0,0 +1 @@
|
||||||
|
from .game import Mutation as GameMutation
|
|
@ -0,0 +1,29 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.types import Game
|
||||||
|
from games.models import Game as GameModel
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateGameMutation(graphene.Mutation):
|
||||||
|
class Arguments:
|
||||||
|
id = graphene.ID(required=True)
|
||||||
|
name = graphene.String()
|
||||||
|
year_released = graphene.Int()
|
||||||
|
wikidata = graphene.String()
|
||||||
|
|
||||||
|
game = graphene.Field(Game)
|
||||||
|
|
||||||
|
def mutate(self, info, id, name=None, year_released=None, wikidata=None):
|
||||||
|
game_instance = GameModel.objects.get(pk=id)
|
||||||
|
if name is not None:
|
||||||
|
game_instance.name = name
|
||||||
|
if year_released is not None:
|
||||||
|
game_instance.year_released = year_released
|
||||||
|
if wikidata is not None:
|
||||||
|
game_instance.wikidata = wikidata
|
||||||
|
game_instance.save()
|
||||||
|
return UpdateGameMutation(game=game_instance)
|
||||||
|
|
||||||
|
|
||||||
|
class Mutation(graphene.ObjectType):
|
||||||
|
update_game = UpdateGameMutation.Field()
|
|
@ -0,0 +1,6 @@
|
||||||
|
from .device import Query as DeviceQuery
|
||||||
|
from .edition import Query as EditionQuery
|
||||||
|
from .game import Query as GameQuery
|
||||||
|
from .platform import Query as PlatformQuery
|
||||||
|
from .purchase import Query as PurchaseQuery
|
||||||
|
from .session import Query as SessionQuery
|
|
@ -0,0 +1,11 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.types import Device
|
||||||
|
from games.models import Device as DeviceModel
|
||||||
|
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
devices = graphene.List(Device)
|
||||||
|
|
||||||
|
def resolve_devices(self, info, **kwargs):
|
||||||
|
return DeviceModel.objects.all()
|
|
@ -0,0 +1,11 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.types import Edition
|
||||||
|
from games.models import Game as EditionModel
|
||||||
|
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
editions = graphene.List(Edition)
|
||||||
|
|
||||||
|
def resolve_editions(self, info, **kwargs):
|
||||||
|
return EditionModel.objects.all()
|
|
@ -0,0 +1,18 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.types import Game
|
||||||
|
from games.models import Game as GameModel
|
||||||
|
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
games = graphene.List(Game)
|
||||||
|
game_by_name = graphene.Field(Game, name=graphene.String(required=True))
|
||||||
|
|
||||||
|
def resolve_games(self, info, **kwargs):
|
||||||
|
return GameModel.objects.all()
|
||||||
|
|
||||||
|
def resolve_game_by_name(self, info, name):
|
||||||
|
try:
|
||||||
|
return GameModel.objects.get(name=name)
|
||||||
|
except GameModel.DoesNotExist:
|
||||||
|
return None
|
|
@ -0,0 +1,11 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.types import Platform
|
||||||
|
from games.models import Platform as PlatformModel
|
||||||
|
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
platforms = graphene.List(Platform)
|
||||||
|
|
||||||
|
def resolve_platforms(self, info, **kwargs):
|
||||||
|
return PlatformModel.objects.all()
|
|
@ -0,0 +1,11 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.types import Purchase
|
||||||
|
from games.models import Purchase as PurchaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
purchases = graphene.List(Purchase)
|
||||||
|
|
||||||
|
def resolve_purchases(self, info, **kwargs):
|
||||||
|
return PurchaseModel.objects.all()
|
|
@ -0,0 +1,11 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.types import Session
|
||||||
|
from games.models import Session as SessionModel
|
||||||
|
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
sessions = graphene.List(Session)
|
||||||
|
|
||||||
|
def resolve_sessions(self, info, **kwargs):
|
||||||
|
return SessionModel.objects.all()
|
|
@ -0,0 +1,44 @@
|
||||||
|
from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
|
from games.models import Device as DeviceModel
|
||||||
|
from games.models import Edition as EditionModel
|
||||||
|
from games.models import Game as GameModel
|
||||||
|
from games.models import Platform as PlatformModel
|
||||||
|
from games.models import Purchase as PurchaseModel
|
||||||
|
from games.models import Session as SessionModel
|
||||||
|
|
||||||
|
|
||||||
|
class Game(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = GameModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class Edition(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = EditionModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class Purchase(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = PurchaseModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class Session(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = SessionModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class Platform(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = PlatformModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class Device(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = DeviceModel
|
||||||
|
fields = "__all__"
|
|
@ -0,0 +1,30 @@
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
from games.graphql.mutations import GameMutation
|
||||||
|
from games.graphql.queries import (
|
||||||
|
DeviceQuery,
|
||||||
|
EditionQuery,
|
||||||
|
GameQuery,
|
||||||
|
PlatformQuery,
|
||||||
|
PurchaseQuery,
|
||||||
|
SessionQuery,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Query(
|
||||||
|
GameQuery,
|
||||||
|
EditionQuery,
|
||||||
|
DeviceQuery,
|
||||||
|
PlatformQuery,
|
||||||
|
PurchaseQuery,
|
||||||
|
SessionQuery,
|
||||||
|
graphene.ObjectType,
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Mutation(GameMutation, graphene.ObjectType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
schema = graphene.Schema(query=Query, mutation=Mutation)
|
|
@ -1,24 +1,24 @@
|
||||||
import { syncSelectInputUntilChanged } from './utils.js';
|
import { syncSelectInputUntilChanged } from "./utils.js";
|
||||||
|
|
||||||
let syncData = [
|
let syncData = [
|
||||||
{
|
{
|
||||||
"source": "#id_game",
|
source: "#id_game",
|
||||||
"source_value": "dataset.name",
|
source_value: "dataset.name",
|
||||||
"target": "#id_name",
|
target: "#id_name",
|
||||||
"target_value": "value"
|
target_value: "value",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"source": "#id_game",
|
source: "#id_game",
|
||||||
"source_value": "textContent",
|
source_value: "textContent",
|
||||||
"target": "#id_sort_name",
|
target: "#id_sort_name",
|
||||||
"target_value": "value"
|
target_value: "value",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"source": "#id_game",
|
source: "#id_game",
|
||||||
"source_value": "dataset.year",
|
source_value: "dataset.year",
|
||||||
"target": "#id_year_released",
|
target: "#id_year_released",
|
||||||
"target_value": "value"
|
target_value: "value",
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
syncSelectInputUntilChanged(syncData, "form");
|
syncSelectInputUntilChanged(syncData, "form");
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { syncSelectInputUntilChanged } from './utils.js'
|
import { syncSelectInputUntilChanged } from "./utils.js";
|
||||||
|
|
||||||
let syncData = [
|
let syncData = [
|
||||||
{
|
{
|
||||||
"source": "#id_name",
|
source: "#id_name",
|
||||||
"source_value": "value",
|
source_value: "value",
|
||||||
"target": "#id_sort_name",
|
target: "#id_sort_name",
|
||||||
"target_value": "value"
|
target_value: "value",
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
syncSelectInputUntilChanged(syncData, "form")
|
syncSelectInputUntilChanged(syncData, "form");
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {
|
||||||
syncSelectInputUntilChanged,
|
syncSelectInputUntilChanged,
|
||||||
getEl,
|
getEl,
|
||||||
disableElementsWhenTrue,
|
disableElementsWhenTrue,
|
||||||
disableElementsWhenFalse,
|
disableElementsWhenValueNotEqual,
|
||||||
} from "./utils.js";
|
} from "./utils.js";
|
||||||
|
|
||||||
let syncData = [
|
let syncData = [
|
||||||
|
@ -21,7 +21,11 @@ function setupElementHandlers() {
|
||||||
"#id_name",
|
"#id_name",
|
||||||
"#id_related_purchase",
|
"#id_related_purchase",
|
||||||
]);
|
]);
|
||||||
disableElementsWhenFalse("#id_type", "game", ["#id_date_finished"]);
|
disableElementsWhenValueNotEqual(
|
||||||
|
"#id_type",
|
||||||
|
["game", "dlc"],
|
||||||
|
["#id_date_finished"]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", setupElementHandlers);
|
document.addEventListener("DOMContentLoaded", setupElementHandlers);
|
||||||
|
@ -30,14 +34,14 @@ getEl("#id_type").onchange = () => {
|
||||||
setupElementHandlers();
|
setupElementHandlers();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.body.addEventListener('htmx:beforeRequest', function(event) {
|
document.body.addEventListener("htmx:beforeRequest", function (event) {
|
||||||
// Assuming 'Purchase1' is the element that triggers the HTMX request
|
// Assuming 'Purchase1' is the element that triggers the HTMX request
|
||||||
if (event.target.id === 'id_edition') {
|
if (event.target.id === "id_edition") {
|
||||||
var idEditionValue = document.getElementById('id_edition').value;
|
var idEditionValue = document.getElementById("id_edition").value;
|
||||||
|
|
||||||
// Condition to check - replace this with your actual logic
|
// Condition to check - replace this with your actual logic
|
||||||
if (idEditionValue != '') {
|
if (idEditionValue != "") {
|
||||||
event.preventDefault(); // This cancels the HTMX request
|
event.preventDefault(); // This cancels the HTMX request
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,10 +7,14 @@ for (let button of document.querySelectorAll("[data-target]")) {
|
||||||
button.addEventListener("click", (event) => {
|
button.addEventListener("click", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (type == "now") {
|
if (type == "now") {
|
||||||
targetElement.value = toISOUTCString(new Date);
|
targetElement.value = toISOUTCString(new Date());
|
||||||
} else if (type == "copy") {
|
} else if (type == "copy") {
|
||||||
const oppositeName = targetElement.name == "timestamp_start" ? "timestamp_end" : "timestamp_start";
|
const oppositeName =
|
||||||
document.querySelector(`[name='${oppositeName}']`).value = targetElement.value;
|
targetElement.name == "timestamp_start"
|
||||||
|
? "timestamp_end"
|
||||||
|
: "timestamp_start";
|
||||||
|
document.querySelector(`[name='${oppositeName}']`).value =
|
||||||
|
targetElement.value;
|
||||||
} else if (type == "toggle") {
|
} else if (type == "toggle") {
|
||||||
if (targetElement.type == "datetime-local") targetElement.type = "text";
|
if (targetElement.type == "datetime-local") targetElement.type = "text";
|
||||||
else targetElement.type = "datetime-local";
|
else targetElement.type = "datetime-local";
|
||||||
|
|
|
@ -75,7 +75,14 @@ function syncSelectInputUntilChanged(syncData, parentSelector = document) {
|
||||||
* @param {string} property - The property to retrieve the value from.
|
* @param {string} property - The property to retrieve the value from.
|
||||||
*/
|
*/
|
||||||
function getValueFromProperty(sourceElement, property) {
|
function getValueFromProperty(sourceElement, property) {
|
||||||
let source = (sourceElement instanceof HTMLSelectElement) ? sourceElement.selectedOptions[0] : sourceElement
|
let source =
|
||||||
|
sourceElement instanceof HTMLSelectElement
|
||||||
|
? sourceElement.selectedOptions[0]
|
||||||
|
: sourceElement;
|
||||||
|
let source =
|
||||||
|
sourceElement instanceof HTMLSelectElement
|
||||||
|
? sourceElement.selectedOptions[0]
|
||||||
|
: sourceElement;
|
||||||
if (property.startsWith("dataset.")) {
|
if (property.startsWith("dataset.")) {
|
||||||
let datasetKey = property.slice(8); // Remove 'dataset.' part
|
let datasetKey = property.slice(8); // Remove 'dataset.' part
|
||||||
return source.dataset[datasetKey];
|
return source.dataset[datasetKey];
|
||||||
|
@ -93,13 +100,11 @@ function getValueFromProperty(sourceElement, property) {
|
||||||
*/
|
*/
|
||||||
function getEl(selector) {
|
function getEl(selector) {
|
||||||
if (selector.startsWith("#")) {
|
if (selector.startsWith("#")) {
|
||||||
return document.getElementById(selector.slice(1))
|
return document.getElementById(selector.slice(1));
|
||||||
}
|
} else if (selector.startsWith(".")) {
|
||||||
else if (selector.startsWith(".")) {
|
return document.getElementsByClassName(selector);
|
||||||
return document.getElementsByClassName(selector)
|
} else {
|
||||||
}
|
return document.getElementsByTagName(selector);
|
||||||
else {
|
|
||||||
return document.getElementsByTagName(selector)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +121,7 @@ function getEl(selector) {
|
||||||
function conditionalElementHandler(...configs) {
|
function conditionalElementHandler(...configs) {
|
||||||
configs.forEach(([condition, targetElements, callbackfn1, callbackfn2]) => {
|
configs.forEach(([condition, targetElements, callbackfn1, callbackfn2]) => {
|
||||||
if (condition()) {
|
if (condition()) {
|
||||||
targetElements.forEach(elementName => {
|
targetElements.forEach((elementName) => {
|
||||||
let el = getEl(elementName);
|
let el = getEl(elementName);
|
||||||
if (el === null) {
|
if (el === null) {
|
||||||
console.error(`Element ${elementName} doesn't exist.`);
|
console.error(`Element ${elementName} doesn't exist.`);
|
||||||
|
@ -125,7 +130,7 @@ function conditionalElementHandler(...configs) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
targetElements.forEach(elementName => {
|
targetElements.forEach((elementName) => {
|
||||||
let el = getEl(elementName);
|
let el = getEl(elementName);
|
||||||
if (el === null) {
|
if (el === null) {
|
||||||
console.error(`Element ${elementName} doesn't exist.`);
|
console.error(`Element ${elementName} doesn't exist.`);
|
||||||
|
@ -137,16 +142,44 @@ function conditionalElementHandler(...configs) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableElementsWhenFalse(targetSelect, targetValue, elementList) {
|
function disableElementsWhenValueNotEqual(
|
||||||
|
targetSelect,
|
||||||
|
targetValue,
|
||||||
|
elementList
|
||||||
|
) {
|
||||||
return conditionalElementHandler([
|
return conditionalElementHandler([
|
||||||
() => {
|
() => {
|
||||||
return getEl(targetSelect).value != targetValue;
|
let target = getEl(targetSelect);
|
||||||
|
console.debug(
|
||||||
|
`${disableElementsWhenTrue.name}: triggered on ${target.id}`
|
||||||
|
);
|
||||||
|
console.debug(`
|
||||||
|
${disableElementsWhenTrue.name}: matching against value(s): ${targetValue}`);
|
||||||
|
if (targetValue instanceof Array) {
|
||||||
|
if (targetValue.every((value) => target.value != value)) {
|
||||||
|
console.debug(
|
||||||
|
`${disableElementsWhenTrue.name}: none of the values is equal to ${target.value}, returning true.`
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.debug(
|
||||||
|
`${disableElementsWhenTrue.name}: none of the values is equal to ${target.value}, returning true.`
|
||||||
|
);
|
||||||
|
return target.value != targetValue;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
elementList,
|
elementList,
|
||||||
(el) => {
|
(el) => {
|
||||||
|
console.debug(
|
||||||
|
`${disableElementsWhenTrue.name}: evaluated true, disabling ${el.id}.`
|
||||||
|
);
|
||||||
el.disabled = "disabled";
|
el.disabled = "disabled";
|
||||||
},
|
},
|
||||||
(el) => {
|
(el) => {
|
||||||
|
console.debug(
|
||||||
|
`${disableElementsWhenTrue.name}: evaluated false, NOT disabling ${el.id}.`
|
||||||
|
);
|
||||||
el.disabled = "";
|
el.disabled = "";
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -167,4 +200,12 @@ function disableElementsWhenTrue(targetSelect, targetValue, elementList) {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { toISOUTCString, syncSelectInputUntilChanged, getEl, conditionalElementHandler, disableElementsWhenFalse, disableElementsWhenTrue, getValueFromProperty };
|
export {
|
||||||
|
toISOUTCString,
|
||||||
|
syncSelectInputUntilChanged,
|
||||||
|
getEl,
|
||||||
|
conditionalElementHandler,
|
||||||
|
disableElementsWhenFalse,
|
||||||
|
disableElementsWhenTrue,
|
||||||
|
getValueFromProperty,
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,19 @@
|
||||||
# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aniso8601"
|
||||||
|
version = "9.0.1"
|
||||||
|
description = "A library for parsing ISO 8601 strings."
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"},
|
||||||
|
{file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asgiref"
|
name = "asgiref"
|
||||||
version = "3.7.2"
|
version = "3.7.2"
|
||||||
|
@ -207,6 +221,75 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1
|
||||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
|
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
|
||||||
typing = ["typing-extensions (>=4.8)"]
|
typing = ["typing-extensions (>=4.8)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphene"
|
||||||
|
version = "3.3"
|
||||||
|
description = "GraphQL Framework for Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "graphene-3.3-py2.py3-none-any.whl", hash = "sha256:bb3810be33b54cb3e6969506671eb72319e8d7ba0d5ca9c8066472f75bf35a38"},
|
||||||
|
{file = "graphene-3.3.tar.gz", hash = "sha256:529bf40c2a698954217d3713c6041d69d3f719ad0080857d7ee31327112446b0"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
aniso8601 = ">=8,<10"
|
||||||
|
graphql-core = ">=3.1,<3.3"
|
||||||
|
graphql-relay = ">=3.1,<3.3"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["black (==22.3.0)", "coveralls (>=3.3,<4)", "flake8 (>=4,<5)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"]
|
||||||
|
test = ["coveralls (>=3.3,<4)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphene-django"
|
||||||
|
version = "3.1.5"
|
||||||
|
description = "Graphene Django integration"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "graphene-django-3.1.5.tar.gz", hash = "sha256:abe42f820b9731d94bebff6d73088d0dc2ffb8c8863a6d7bf3d378412d866a3b"},
|
||||||
|
{file = "graphene_django-3.1.5-py2.py3-none-any.whl", hash = "sha256:2e42742fae21fa50e514f3acae26a9bc6cb5e51c179a97b3db5390ff258ca816"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Django = ">=3.2"
|
||||||
|
graphene = ">=3.0,<4"
|
||||||
|
graphql-core = ">=3.1.0,<4"
|
||||||
|
graphql-relay = ">=3.1.1,<4"
|
||||||
|
promise = ">=2.1"
|
||||||
|
text-unidecode = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["black (==23.7.0)", "coveralls", "django-filter (>=22.1)", "djangorestframework (>=3.6.3)", "mock", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-django (>=4.5.2)", "pytest-random-order", "pytz", "ruff (==0.0.283)"]
|
||||||
|
rest-framework = ["djangorestframework (>=3.6.3)"]
|
||||||
|
test = ["coveralls", "django-filter (>=22.1)", "djangorestframework (>=3.6.3)", "mock", "pytest (>=7.3.1)", "pytest-cov", "pytest-django (>=4.5.2)", "pytest-random-order", "pytz"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphql-core"
|
||||||
|
version = "3.2.3"
|
||||||
|
description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6,<4"
|
||||||
|
files = [
|
||||||
|
{file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"},
|
||||||
|
{file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphql-relay"
|
||||||
|
version = "3.2.0"
|
||||||
|
description = "Relay library for graphql-core"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6,<4"
|
||||||
|
files = [
|
||||||
|
{file = "graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c"},
|
||||||
|
{file = "graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
graphql-core = ">=3.2,<3.3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gunicorn"
|
name = "gunicorn"
|
||||||
version = "20.1.0"
|
version = "20.1.0"
|
||||||
|
@ -262,13 +345,13 @@ files = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "identify"
|
name = "identify"
|
||||||
version = "2.5.31"
|
version = "2.5.32"
|
||||||
description = "File identification library for Python"
|
description = "File identification library for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"},
|
{file = "identify-2.5.32-py2.py3-none-any.whl", hash = "sha256:0b7656ef6cba81664b783352c73f8c24b39cf82f926f78f4550eda928e5e0545"},
|
||||||
{file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"},
|
{file = "identify-2.5.32.tar.gz", hash = "sha256:5d9979348ec1a21c768ae07e0a652924538e8bce67313a73cb0f681cf08ba407"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
|
@ -543,6 +626,22 @@ nodeenv = ">=0.11.1"
|
||||||
pyyaml = ">=5.1"
|
pyyaml = ">=5.1"
|
||||||
virtualenv = ">=20.10.0"
|
virtualenv = ">=20.10.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "promise"
|
||||||
|
version = "2.3"
|
||||||
|
description = "Promises/A+ implementation for Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "promise-2.3.tar.gz", hash = "sha256:dfd18337c523ba4b6a58801c164c1904a9d4d1b1747c7d5dbf45b693a49d93d0"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
six = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["coveralls", "futures", "mock", "pytest (>=2.7.3)", "pytest-benchmark", "pytest-cov"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "7.4.3"
|
version = "7.4.3"
|
||||||
|
@ -762,6 +861,17 @@ dev = ["build", "flake8"]
|
||||||
doc = ["sphinx"]
|
doc = ["sphinx"]
|
||||||
test = ["pytest", "pytest-cov"]
|
test = ["pytest", "pytest-cov"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "text-unidecode"
|
||||||
|
version = "1.3"
|
||||||
|
description = "The most basic Text::Unidecode port"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
|
||||||
|
{file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tqdm"
|
name = "tqdm"
|
||||||
version = "4.66.1"
|
version = "4.66.1"
|
||||||
|
@ -862,4 +972,4 @@ watchdog = ["watchdog (>=2.3)"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.12"
|
python-versions = "^3.12"
|
||||||
content-hash = "32e7c40e7148530effb10ebd5d67a4f1c8fe30794a4d3b5d213d4f30048c79ea"
|
content-hash = "49b33333953d875c6c2a26ffd1a1a2d21f75e06fe59e6619ba2900e39d2cf1bf"
|
||||||
|
|
|
@ -12,6 +12,7 @@ python = "^3.12"
|
||||||
django = "^4.2.0"
|
django = "^4.2.0"
|
||||||
gunicorn = "^20.1.0"
|
gunicorn = "^20.1.0"
|
||||||
uvicorn = "^0.20.0"
|
uvicorn = "^0.20.0"
|
||||||
|
graphene-django = "^3.1.5"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^22.12.0"
|
black = "^22.12.0"
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
import django
|
||||||
|
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "timetracker.settings")
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
from graphene_django.utils.testing import GraphQLTestCase
|
||||||
|
|
||||||
|
from games import schema
|
||||||
|
from games.models import Game
|
||||||
|
|
||||||
|
|
||||||
|
class GameAPITestCase(GraphQLTestCase):
|
||||||
|
GRAPHENE_SCHEMA = schema.schema
|
||||||
|
|
||||||
|
def test_query_all_games(self):
|
||||||
|
response = self.query(
|
||||||
|
"""
|
||||||
|
query {
|
||||||
|
games {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertResponseNoErrors(response)
|
||||||
|
self.assertEqual(
|
||||||
|
len(json.loads(response.content)["data"]["games"]),
|
||||||
|
Game.objects.count(),
|
||||||
|
)
|
|
@ -38,8 +38,11 @@ INSTALLED_APPS = [
|
||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
|
"graphene_django",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
GRAPHENE = {"SCHEMA": "games.schema.schema"}
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
INSTALLED_APPS.append("django_extensions")
|
INSTALLED_APPS.append("django_extensions")
|
||||||
INSTALLED_APPS.append("django.contrib.admin")
|
INSTALLED_APPS.append("django.contrib.admin")
|
||||||
|
|
|
@ -16,11 +16,14 @@ Including another URLconf
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
|
from graphene_django.views import GraphQLView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", RedirectView.as_view(url="/tracker")),
|
path("", RedirectView.as_view(url="/tracker")),
|
||||||
path("tracker/", include("games.urls")),
|
path("tracker/", include("games.urls")),
|
||||||
|
path("graphql", csrf_exempt(GraphQLView.as_view(graphiql=True))),
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
Loading…
Reference in New Issue