mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-22 06:03:20 +00:00
Graph de famille en frontend (#820)
* Remove graphviz and use cytoscape.js instead * Frontend generated graphs * Make installation easier and faster * Better user experience * Family api and improved interface * Fix url history when using 0, improve button selection and reset reverse with reset button * Use klay layout * Add js translations and apply review comments
This commit is contained in:
parent
bf96d8a10c
commit
f624b7c66d
4
.github/actions/setup_project/action.yml
vendored
4
.github/actions/setup_project/action.yml
vendored
@ -6,13 +6,13 @@ runs:
|
|||||||
- name: Install apt packages
|
- name: Install apt packages
|
||||||
uses: awalsh128/cache-apt-pkgs-action@latest
|
uses: awalsh128/cache-apt-pkgs-action@latest
|
||||||
with:
|
with:
|
||||||
packages: gettext libgraphviz-dev
|
packages: gettext
|
||||||
version: 1.0 # increment to reset cache
|
version: 1.0 # increment to reset cache
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install gettext libgraphviz-dev
|
sudo apt install gettext
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Set up python
|
- name: Set up python
|
||||||
|
53
core/api.py
53
core/api.py
@ -1,10 +1,19 @@
|
|||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
import annotated_types
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from ninja_extra import ControllerBase, api_controller, route
|
from ninja_extra import ControllerBase, api_controller, route
|
||||||
from ninja_extra.exceptions import PermissionDenied
|
from ninja_extra.exceptions import PermissionDenied
|
||||||
|
|
||||||
from club.models import Mailing
|
from club.models import Mailing
|
||||||
from core.schemas import MarkdownSchema
|
from core.api_permissions import CanView
|
||||||
|
from core.models import User
|
||||||
|
from core.schemas import (
|
||||||
|
FamilyGodfatherSchema,
|
||||||
|
MarkdownSchema,
|
||||||
|
UserFamilySchema,
|
||||||
|
)
|
||||||
from core.templatetags.renderer import markdown
|
from core.templatetags.renderer import markdown
|
||||||
|
|
||||||
|
|
||||||
@ -27,3 +36,45 @@ class MailingListController(ControllerBase):
|
|||||||
).prefetch_related("subscriptions")
|
).prefetch_related("subscriptions")
|
||||||
data = "\n".join(m.fetch_format() for m in mailings)
|
data = "\n".join(m.fetch_format() for m in mailings)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
DepthValue = Annotated[int, annotated_types.Ge(0), annotated_types.Le(10)]
|
||||||
|
DEFAULT_DEPTH = 4
|
||||||
|
|
||||||
|
|
||||||
|
@api_controller("/family")
|
||||||
|
class FamilyController(ControllerBase):
|
||||||
|
@route.get(
|
||||||
|
"/{user_id}",
|
||||||
|
permissions=[CanView],
|
||||||
|
response=UserFamilySchema,
|
||||||
|
url_name="family_graph",
|
||||||
|
)
|
||||||
|
def get_family_graph(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
godfathers_depth: DepthValue = DEFAULT_DEPTH,
|
||||||
|
godchildren_depth: DepthValue = DEFAULT_DEPTH,
|
||||||
|
):
|
||||||
|
user: User = self.get_object_or_exception(User, pk=user_id)
|
||||||
|
|
||||||
|
relations = user.get_family(godfathers_depth, godchildren_depth)
|
||||||
|
if not relations:
|
||||||
|
# If the user has no relations, return only the user
|
||||||
|
# He is alone in its family, but the family exists nonetheless
|
||||||
|
return {"users": [user], "relationships": []}
|
||||||
|
|
||||||
|
user_ids = {r.from_user_id for r in relations} | {
|
||||||
|
r.to_user_id for r in relations
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"users": User.objects.filter(id__in=user_ids).distinct(),
|
||||||
|
"relationships": (
|
||||||
|
[
|
||||||
|
FamilyGodfatherSchema(
|
||||||
|
godchild=r.from_user_id, godfather=r.to_user_id
|
||||||
|
)
|
||||||
|
for r in relations
|
||||||
|
]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
@ -78,7 +78,7 @@ class CanView(BasePermission):
|
|||||||
"""Check that this user has the permission to view the object of this route.
|
"""Check that this user has the permission to view the object of this route.
|
||||||
|
|
||||||
Wrap the `user.can_view(obj)` method.
|
Wrap the `user.can_view(obj)` method.
|
||||||
To see an example, look at the exemple in the module docstring.
|
To see an example, look at the example in the module docstring.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
|
def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
|
||||||
@ -94,7 +94,7 @@ class CanEdit(BasePermission):
|
|||||||
"""Check that this user has the permission to edit the object of this route.
|
"""Check that this user has the permission to edit the object of this route.
|
||||||
|
|
||||||
Wrap the `user.can_edit(obj)` method.
|
Wrap the `user.can_edit(obj)` method.
|
||||||
To see an example, look at the exemple in the module docstring.
|
To see an example, look at the example in the module docstring.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
|
def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
|
||||||
@ -110,7 +110,7 @@ class IsOwner(BasePermission):
|
|||||||
"""Check that this user owns the object of this route.
|
"""Check that this user owns the object of this route.
|
||||||
|
|
||||||
Wrap the `user.is_owner(obj)` method.
|
Wrap the `user.is_owner(obj)` method.
|
||||||
To see an example, look at the exemple in the module docstring.
|
To see an example, look at the example in the module docstring.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
|
def has_permission(self, request: HttpRequest, controller: ControllerBase) -> bool:
|
||||||
|
@ -57,6 +57,7 @@ from django.utils.functional import cached_property
|
|||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
from phonenumber_field.modelfields import PhoneNumberField
|
||||||
|
from pydantic.v1 import NonNegativeInt
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from club.models import Club
|
from club.models import Club
|
||||||
@ -606,6 +607,41 @@ class User(AbstractBaseUser):
|
|||||||
today.year - born.year - ((today.month, today.day) < (born.month, born.day))
|
today.year - born.year - ((today.month, today.day) < (born.month, born.day))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_family(
|
||||||
|
self,
|
||||||
|
godfathers_depth: NonNegativeInt = 4,
|
||||||
|
godchildren_depth: NonNegativeInt = 4,
|
||||||
|
) -> set[User.godfathers.through]:
|
||||||
|
"""Get the family of the user, with the given depth.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
godfathers_depth: The number of generations of godfathers to fetch
|
||||||
|
godchildren_depth: The number of generations of godchildren to fetch
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of family relationships in this user's family
|
||||||
|
"""
|
||||||
|
res = []
|
||||||
|
for depth, key, reverse_key in [
|
||||||
|
(godfathers_depth, "from_user_id", "to_user_id"),
|
||||||
|
(godchildren_depth, "to_user_id", "from_user_id"),
|
||||||
|
]:
|
||||||
|
if depth == 0:
|
||||||
|
continue
|
||||||
|
links = list(User.godfathers.through.objects.filter(**{key: self.id}))
|
||||||
|
res.extend(links)
|
||||||
|
for _ in range(1, depth):
|
||||||
|
ids = [getattr(c, reverse_key) for c in links]
|
||||||
|
links = list(
|
||||||
|
User.godfathers.through.objects.filter(
|
||||||
|
**{f"{key}__in": ids}
|
||||||
|
).exclude(id__in=[r.id for r in res])
|
||||||
|
)
|
||||||
|
if not links:
|
||||||
|
break
|
||||||
|
res.extend(links)
|
||||||
|
return set(res)
|
||||||
|
|
||||||
def email_user(self, subject, message, from_email=None, **kwargs):
|
def email_user(self, subject, message, from_email=None, **kwargs):
|
||||||
"""Sends an email to this User."""
|
"""Sends an email to this User."""
|
||||||
if from_email is None:
|
if from_email is None:
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||||
from ninja import ModelSchema, Schema
|
from ninja import ModelSchema, Schema
|
||||||
|
|
||||||
from core.models import User
|
from core.models import User
|
||||||
@ -13,3 +14,41 @@ class SimpleUserSchema(ModelSchema):
|
|||||||
|
|
||||||
class MarkdownSchema(Schema):
|
class MarkdownSchema(Schema):
|
||||||
text: str
|
text: str
|
||||||
|
|
||||||
|
|
||||||
|
class UserProfileSchema(ModelSchema):
|
||||||
|
"""The necessary information to show a user profile"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = ["id", "nick_name", "first_name", "last_name"]
|
||||||
|
|
||||||
|
display_name: str
|
||||||
|
profile_url: str
|
||||||
|
profile_pict: str
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_display_name(obj: User) -> str:
|
||||||
|
return obj.get_display_name()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_profile_url(obj: User) -> str:
|
||||||
|
return obj.get_absolute_url()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_profile_pict(obj: User) -> str:
|
||||||
|
if obj.profile_pict_id is None:
|
||||||
|
return staticfiles_storage.url("core/img/unknown.jpg")
|
||||||
|
return obj.profile_pict.get_download_url()
|
||||||
|
|
||||||
|
|
||||||
|
class FamilyGodfatherSchema(Schema):
|
||||||
|
godfather: int
|
||||||
|
godchild: int
|
||||||
|
|
||||||
|
|
||||||
|
class UserFamilySchema(Schema):
|
||||||
|
"""Represent a graph of a user's family"""
|
||||||
|
|
||||||
|
users: list[UserProfileSchema]
|
||||||
|
relationships: list[FamilyGodfatherSchema]
|
||||||
|
@ -89,7 +89,7 @@ function update_query_string(key, value, action = History.REPLACE, url = null) {
|
|||||||
if (!url){
|
if (!url){
|
||||||
url = new URL(window.location.href);
|
url = new URL(window.location.href);
|
||||||
}
|
}
|
||||||
if (!value) {
|
if (value === undefined || value === null || value === "") {
|
||||||
// If the value is null, undefined or empty => delete it
|
// If the value is null, undefined or empty => delete it
|
||||||
url.searchParams.delete(key)
|
url.searchParams.delete(key)
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
|
@ -239,6 +239,7 @@ a:not(.button) {
|
|||||||
padding: 9px 13px;
|
padding: 9px 13px;
|
||||||
border: none;
|
border: none;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
&.btn-blue {
|
&.btn-blue {
|
||||||
background-color: $deepblue;
|
background-color: $deepblue;
|
||||||
|
267
core/static/user/js/family_graph.js
Normal file
267
core/static/user/js/family_graph.js
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
async function get_graph_data(url, godfathers_depth, godchildren_depth) {
|
||||||
|
let data = await (
|
||||||
|
await fetch(
|
||||||
|
`${url}?godfathers_depth=${godfathers_depth}&godchildren_depth=${godchildren_depth}`,
|
||||||
|
)
|
||||||
|
).json();
|
||||||
|
return [
|
||||||
|
...data.users.map((user) => {
|
||||||
|
return { data: user };
|
||||||
|
}),
|
||||||
|
...data.relationships.map((rel) => {
|
||||||
|
return {
|
||||||
|
data: { source: rel.godfather, target: rel.godchild },
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_graph(container, data, active_user_id) {
|
||||||
|
let cy = cytoscape({
|
||||||
|
boxSelectionEnabled: false,
|
||||||
|
autounselectify: true,
|
||||||
|
|
||||||
|
container: container,
|
||||||
|
elements: data,
|
||||||
|
minZoom: 0.5,
|
||||||
|
|
||||||
|
style: [
|
||||||
|
// the stylesheet for the graph
|
||||||
|
{
|
||||||
|
selector: "node",
|
||||||
|
style: {
|
||||||
|
label: "data(display_name)",
|
||||||
|
"background-image": "data(profile_pict)",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
"background-fit": "cover",
|
||||||
|
"background-repeat": "no-repeat",
|
||||||
|
shape: "ellipse",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
selector: "edge",
|
||||||
|
style: {
|
||||||
|
width: 5,
|
||||||
|
"line-color": "#ccc",
|
||||||
|
"target-arrow-color": "#ccc",
|
||||||
|
"target-arrow-shape": "triangle",
|
||||||
|
"curve-style": "bezier",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
selector: ".traversed",
|
||||||
|
style: {
|
||||||
|
"border-width": "5px",
|
||||||
|
"border-style": "solid",
|
||||||
|
"border-color": "red",
|
||||||
|
"target-arrow-color": "red",
|
||||||
|
"line-color": "red",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
selector: ".not-traversed",
|
||||||
|
style: {
|
||||||
|
"line-opacity": "0.5",
|
||||||
|
"background-opacity": "0.5",
|
||||||
|
"background-image-opacity": "0.5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
layout: {
|
||||||
|
name: "klay",
|
||||||
|
nodeDimensionsIncludeLabels: true,
|
||||||
|
fit: true,
|
||||||
|
klay: {
|
||||||
|
addUnnecessaryBendpoints: true,
|
||||||
|
direction: 'DOWN',
|
||||||
|
nodePlacement: 'INTERACTIVE',
|
||||||
|
layoutHierarchy: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let active_user = cy
|
||||||
|
.getElementById(active_user_id)
|
||||||
|
.style("shape", "rectangle");
|
||||||
|
/* Reset graph */
|
||||||
|
let reset_graph = () => {
|
||||||
|
cy.elements((element) => {
|
||||||
|
if (element.hasClass("traversed")) {
|
||||||
|
element.removeClass("traversed");
|
||||||
|
}
|
||||||
|
if (element.hasClass("not-traversed")) {
|
||||||
|
element.removeClass("not-traversed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let on_node_tap = (el) => {
|
||||||
|
reset_graph();
|
||||||
|
/* Create path on graph if selected isn't the targeted user */
|
||||||
|
if (el === active_user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cy.elements((element) => {
|
||||||
|
element.addClass("not-traversed");
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.elements()
|
||||||
|
.aStar({
|
||||||
|
root: el,
|
||||||
|
goal: active_user,
|
||||||
|
})
|
||||||
|
.path.forEach((el) => {
|
||||||
|
el.removeClass("not-traversed");
|
||||||
|
el.addClass("traversed");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
cy.on("tap", "node", (tapped) => {
|
||||||
|
on_node_tap(tapped.target);
|
||||||
|
});
|
||||||
|
cy.zoomingEnabled(false);
|
||||||
|
|
||||||
|
/* Add context menu */
|
||||||
|
if (cy.cxtmenu === undefined) {
|
||||||
|
console.error(
|
||||||
|
"ctxmenu isn't loaded, context menu won't be available on graphs",
|
||||||
|
);
|
||||||
|
return cy;
|
||||||
|
}
|
||||||
|
cy.cxtmenu({
|
||||||
|
selector: "node",
|
||||||
|
|
||||||
|
commands: [
|
||||||
|
{
|
||||||
|
content: '<i class="fa fa-external-link fa-2x"></i>',
|
||||||
|
select: function (el) {
|
||||||
|
window.open(el.data().profile_url, "_blank").focus();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
content: '<span class="fa fa-mouse-pointer fa-2x"></span>',
|
||||||
|
select: function (el) {
|
||||||
|
on_node_tap(el);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
content: '<i class="fa fa-eraser fa-2x"></i>',
|
||||||
|
select: function (el) {
|
||||||
|
reset_graph();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
return cy;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("alpine:init", () => {
|
||||||
|
/*
|
||||||
|
This needs some constants to be set before the document has been loaded
|
||||||
|
|
||||||
|
api_url: base url for fetching the tree as a string
|
||||||
|
active_user: id of the user to fetch the tree from
|
||||||
|
depth_min: minimum tree depth for godfathers and godchildren as an int
|
||||||
|
depth_max: maximum tree depth for godfathers and godchildren as an int
|
||||||
|
*/
|
||||||
|
const default_depth = 2;
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof api_url === "undefined" ||
|
||||||
|
typeof active_user === "undefined" ||
|
||||||
|
typeof depth_min === "undefined" ||
|
||||||
|
typeof depth_max === "undefined"
|
||||||
|
) {
|
||||||
|
console.error("Some constants are not set before using the family_graph script, please look at the documentation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_initial_depth(prop) {
|
||||||
|
let value = parseInt(initialUrlParams.get(prop));
|
||||||
|
if (isNaN(value) || value < depth_min || value > depth_max) {
|
||||||
|
return default_depth;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Alpine.data("graph", () => ({
|
||||||
|
loading: false,
|
||||||
|
godfathers_depth: get_initial_depth("godfathers_depth"),
|
||||||
|
godchildren_depth: get_initial_depth("godchildren_depth"),
|
||||||
|
reverse: initialUrlParams.get("reverse")?.toLowerCase?.() === 'true',
|
||||||
|
graph: undefined,
|
||||||
|
graph_data: {},
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
let delayed_fetch = Alpine.debounce(async () => {
|
||||||
|
this.fetch_graph_data();
|
||||||
|
}, 100);
|
||||||
|
["godfathers_depth", "godchildren_depth"].forEach((param) => {
|
||||||
|
this.$watch(param, async (value) => {
|
||||||
|
if (value < depth_min || value > depth_max) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
update_query_string(param, value, History.REPLACE);
|
||||||
|
delayed_fetch();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.$watch("reverse", async (value) => {
|
||||||
|
update_query_string("reverse", value, History.REPLACE);
|
||||||
|
this.reverse_graph();
|
||||||
|
});
|
||||||
|
this.$watch("graph_data", async () => {
|
||||||
|
await this.generate_graph();
|
||||||
|
if (this.reverse) {
|
||||||
|
await this.reverse_graph();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.fetch_graph_data();
|
||||||
|
},
|
||||||
|
|
||||||
|
async screenshot() {
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = this.graph.jpg();
|
||||||
|
link.download = gettext("family_tree.%(extension)s", "jpg");
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
},
|
||||||
|
|
||||||
|
async reset() {
|
||||||
|
this.reverse = false;
|
||||||
|
this.godfathers_depth = default_depth;
|
||||||
|
this.godchildren_depth = default_depth;
|
||||||
|
},
|
||||||
|
|
||||||
|
async reverse_graph() {
|
||||||
|
this.graph.elements((el) => {
|
||||||
|
el.position(new Object({ x: -el.position().x, y: -el.position().y }));
|
||||||
|
});
|
||||||
|
this.graph.center(this.graph.elements());
|
||||||
|
},
|
||||||
|
|
||||||
|
async fetch_graph_data() {
|
||||||
|
this.graph_data = await get_graph_data(
|
||||||
|
api_url,
|
||||||
|
this.godfathers_depth,
|
||||||
|
this.godchildren_depth,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
async generate_graph() {
|
||||||
|
this.loading = true;
|
||||||
|
this.graph = create_graph(
|
||||||
|
$(this.$refs.graph),
|
||||||
|
this.graph_data,
|
||||||
|
active_user,
|
||||||
|
);
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
@ -1,3 +1,85 @@
|
|||||||
|
.graph {
|
||||||
|
width: 100%;
|
||||||
|
height: 70vh;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-toolbar {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 30px;
|
||||||
|
|
||||||
|
.toolbar-column{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
min-width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-input {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
label {
|
||||||
|
max-width: 70%;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.depth-choice {
|
||||||
|
white-space: nowrap;
|
||||||
|
input[type="number"] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
appearance: textfield;
|
||||||
|
&::-webkit-inner-spin-button,
|
||||||
|
&::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background: none;
|
||||||
|
& > .fa {
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
&:enabled > .fa {
|
||||||
|
background-color: #354a5f;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
&:enabled:hover > .fa {
|
||||||
|
color: white;
|
||||||
|
background-color: #35405f; // just a bit darker
|
||||||
|
}
|
||||||
|
&:disabled > .fa {
|
||||||
|
background-color: gray;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
align-self: center;
|
||||||
|
max-width: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
.toolbar-column {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -9,6 +91,14 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#family-tree-link {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 10px;
|
||||||
|
text-align: center;
|
||||||
|
@media (min-width: 450px) {
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.users {
|
.users {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -90,7 +180,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-of-type {
|
&.delete {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -98,7 +188,7 @@
|
|||||||
|
|
||||||
@media (max-width: 375px) {
|
@media (max-width: 375px) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0%;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
core/static/vendored/cytoscape/cytoscape-cxtmenu.min.js
vendored
Normal file
7
core/static/vendored/cytoscape/cytoscape-cxtmenu.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
core/static/vendored/cytoscape/cytoscape-klay.min.js
vendored
Normal file
7
core/static/vendored/cytoscape/cytoscape-klay.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
32
core/static/vendored/cytoscape/cytoscape.min.js
vendored
Normal file
32
core/static/vendored/cytoscape/cytoscape.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
core/static/vendored/cytoscape/klay.min.js
vendored
Normal file
7
core/static/vendored/cytoscape/klay.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -112,7 +112,7 @@
|
|||||||
|
|
||||||
{% macro delete_godfather(user, profile, godfather, is_father) %}
|
{% macro delete_godfather(user, profile, godfather, is_father) %}
|
||||||
{% if user == profile or user.is_root or user.is_board_member %}
|
{% if user == profile or user.is_root or user.is_board_member %}
|
||||||
<a href="{{ url("core:user_godfathers_delete", user_id=profile.id, godfather_id=godfather.id, is_father=is_father) }}">{% trans %}Delete{% endtrans %}</a>
|
<a class="delete" href="{{ url("core:user_godfathers_delete", user_id=profile.id, godfather_id=godfather.id, is_father=is_father) }}">{% trans %}Delete{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
@ -11,14 +11,20 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="{{ url('core:user_godfathers_tree_pict', user_id=profile.id) }}?family">
|
{% if godchildren or godfathers %}
|
||||||
{% trans %}Show family picture{% endtrans %}
|
<a
|
||||||
</a>
|
href="{{ url('core:user_godfathers_tree', user_id=profile.id) }}"
|
||||||
|
class="btn btn-blue"
|
||||||
|
id="family-tree-link"
|
||||||
|
>
|
||||||
|
{% trans %}Show family tree{% endtrans %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h4>{% trans %}Godfathers / Godmothers{% endtrans %}</h4>
|
<h4>{% trans %}Godfathers / Godmothers{% endtrans %}</h4>
|
||||||
{% if profile.godfathers.exists() %}
|
{% if godfathers %}
|
||||||
<ul class="users">
|
<ul class="users">
|
||||||
{% for u in profile.godfathers.all() %}
|
{% for u in godfathers %}
|
||||||
<li class="users-card">
|
<li class="users-card">
|
||||||
<a href="{{ url('core:user_godfathers', user_id=u.id) }}" class="mini_profile_link">
|
<a href="{{ url('core:user_godfathers', user_id=u.id) }}" class="mini_profile_link">
|
||||||
{{ u.get_mini_item() | safe }}
|
{{ u.get_mini_item() | safe }}
|
||||||
@ -28,17 +34,14 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a href="{{ url('core:user_godfathers_tree', user_id=profile.id) }}">
|
|
||||||
{% trans %}Show ancestors tree{% endtrans %}
|
|
||||||
</a>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans %}No godfathers / godmothers{% endtrans %}
|
<p>{% trans %}No godfathers / godmothers{% endtrans %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h4>{% trans %}Godchildren{% endtrans %}</h4>
|
<h4>{% trans %}Godchildren{% endtrans %}</h4>
|
||||||
{% if profile.godchildren.exists() %}
|
{% if godchildren %}
|
||||||
<ul class="users">
|
<ul class="users">
|
||||||
{% for u in profile.godchildren.all() %}
|
{% for u in godchildren %}
|
||||||
<li class="users-card">
|
<li class="users-card">
|
||||||
<a href="{{ url('core:user_godfathers', user_id=u.id) }}" class="mini_profile_link">
|
<a href="{{ url('core:user_godfathers', user_id=u.id) }}" class="mini_profile_link">
|
||||||
{{ u.get_mini_item()|safe }}
|
{{ u.get_mini_item()|safe }}
|
||||||
@ -47,10 +50,6 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a href="{{ url('core:user_godfathers_tree', user_id=profile.id) }}?descent">
|
|
||||||
{% trans %}Show descent tree{% endtrans %}
|
|
||||||
</a>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans %}No godchildren{% endtrans %}
|
<p>{% trans %}No godchildren{% endtrans %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,54 +1,105 @@
|
|||||||
{% extends "core/base.jinja" %}
|
{% extends "core/base.jinja" %}
|
||||||
|
{% set depth_min=0 %}
|
||||||
|
{% set depth_max=10 %}
|
||||||
|
|
||||||
|
{%- block additional_css -%}
|
||||||
|
<link rel="stylesheet" href="{{ scss('user/user_godfathers.scss') }}">
|
||||||
|
{%- endblock -%}
|
||||||
|
|
||||||
|
{% block additional_js %}
|
||||||
|
<script src="{{ static("vendored/cytoscape/cytoscape.min.js") }}" defer></script>
|
||||||
|
<script src="{{ static("vendored/cytoscape/cytoscape-cxtmenu.min.js") }}" defer></script>
|
||||||
|
|
||||||
|
<script src="{{ static("vendored/cytoscape/klay.min.js") }}" defer></script>
|
||||||
|
<script src="{{ static("vendored/cytoscape/cytoscape-klay.min.js") }}" defer></script>
|
||||||
|
|
||||||
|
<script src="{{ static("user/js/family_graph.js") }}" defer></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% if param == "godchildren" %}
|
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s family tree{% endtrans %}
|
||||||
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s godchildren{% endtrans %}
|
|
||||||
{% else %}
|
|
||||||
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s godfathers{% endtrans %}
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% macro display_members_list(user) %}
|
|
||||||
{% if user.__getattribute__(param).exists() %}
|
|
||||||
<ul>
|
|
||||||
{% for u in user.__getattribute__(param).all() %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ url("core:user_godfathers", user_id=u.id) }}">
|
|
||||||
{{ u.get_short_name() }}
|
|
||||||
</a>
|
|
||||||
{% if u in members_set %}
|
|
||||||
{% trans %}Already seen (check above){% endtrans %}
|
|
||||||
{% else %}
|
|
||||||
{{ members_set.add(u) or "" }}
|
|
||||||
{{ display_members_list(u) }}
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<p><a href="{{ url("core:user_godfathers", user_id=profile.id) }}">
|
<div x-data="graph" :aria-busy="loading">
|
||||||
{% trans %}Back to family{% endtrans %}</a></p>
|
<div class="graph-toolbar">
|
||||||
{% if profile.__getattribute__(param).exists() %}
|
<div class="toolbar-column">
|
||||||
{% if param == "godchildren" %}
|
<div class="toolbar-input">
|
||||||
<p><a href="{{ url("core:user_godfathers_tree_pict", user_id=profile.id) }}?descent">
|
<label for="godfather-depth-input">
|
||||||
{% trans %}Show a picture of the tree{% endtrans %}</a></p>
|
{% trans min=depth_min, max=depth_max %}Max godfather depth between {{ min }} and {{ max }}{% endtrans %}
|
||||||
<h4>{% trans u=profile.get_short_name() %}Descent tree of {{ u }}{% endtrans %}</h4>
|
</label>
|
||||||
{% else %}
|
<span class="depth-choice">
|
||||||
<p><a href="{{ url("core:user_godfathers_tree_pict", user_id=profile.id) }}?ancestors">
|
<button
|
||||||
{% trans %}Show a picture of the tree{% endtrans %}</a></p>
|
@click="godfathers_depth--"
|
||||||
<h4>{% trans u=profile.get_short_name() %}Ancestors tree of {{ u }}{% endtrans %}</h4>
|
:disabled="godfathers_depth <= {{ depth_min }}"
|
||||||
{% endif %}
|
><i class="fa fa-minus fa-xs"></i></button>
|
||||||
{{ members_set.add(profile) or "" }}
|
<input
|
||||||
{{ display_members_list(profile) }}
|
x-model="godfathers_depth"
|
||||||
{% else %}
|
x-ref="godfather_depth_input"
|
||||||
{% if param == "godchildren" %}
|
type="number"
|
||||||
<p>{% trans %}No godchildren{% endtrans %}
|
name="godfathers_depth"
|
||||||
{% else %}
|
id="godfather-depth-input"
|
||||||
<p>{% trans %}No godfathers / godmothers{% endtrans %}
|
min="{{ depth_min }}"
|
||||||
{% endif %}
|
max="{{ depth_max }}"
|
||||||
{% endif %}
|
/>
|
||||||
|
<button
|
||||||
|
@click="godfathers_depth++"
|
||||||
|
:disabled="godfathers_depth >= {{ depth_max }}"
|
||||||
|
><i class="fa fa-plus"
|
||||||
|
></i></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="toolbar-input">
|
||||||
|
<label for="godchild-depth-input">
|
||||||
|
{% trans min=depth_min, max=depth_max %}Max godchildren depth between {{ min }} and {{ max }}{% endtrans %}
|
||||||
|
</label>
|
||||||
|
<span class="depth-choice">
|
||||||
|
<button
|
||||||
|
@click="godchildren_depth--"
|
||||||
|
:disabled="godchildren_depth <= {{ depth_min }}"
|
||||||
|
><i
|
||||||
|
class="fa fa-minus fa-xs"
|
||||||
|
></i></button>
|
||||||
|
<input
|
||||||
|
x-model="godchildren_depth"
|
||||||
|
type="number"
|
||||||
|
name="godchildren_depth"
|
||||||
|
id="godchild-depth-input"
|
||||||
|
min="{{ depth_min }}"
|
||||||
|
max="{{ depth_max }}"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
@click="godchildren_depth++"
|
||||||
|
:disabled="godchildren_depth >= {{ depth_max }}"
|
||||||
|
><i class="fa fa-plus"
|
||||||
|
></i></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="toolbar-column">
|
||||||
|
<div class="toolbar-input">
|
||||||
|
<label for="reverse-checkbox">{% trans %}Reverse{% endtrans %}</label>
|
||||||
|
<input x-model="reverse" type="checkbox" name="reverse" id="reverse-checkbox">
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-grey" @click="reset">
|
||||||
|
{% trans %}Reset{% endtrans %}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-grey" @click="screenshot">
|
||||||
|
<i class="fa fa-camera"></i>
|
||||||
|
{% trans %}Save{% endtrans %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div x-ref="graph" class="graph"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const api_url = "{{ api_url }}";
|
||||||
|
const active_user = "{{ object.id }}"
|
||||||
|
const depth_min = {{ depth_min }};
|
||||||
|
const depth_max = {{ depth_max }};
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
0
core/tests/__init__.py
Normal file
0
core/tests/__init__.py
Normal file
187
core/tests/test_family.py
Normal file
187
core/tests/test_family.py
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
from model_bakery import baker
|
||||||
|
|
||||||
|
from core.baker_recipes import subscriber_user
|
||||||
|
from core.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class TestFetchFamilyApi(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
# Relations (A -> B means A is the godchild of B):
|
||||||
|
# main_user -> user0 -> user3
|
||||||
|
# -> user1 -> user6 -> user7 -> user8 -> user9
|
||||||
|
# -> user2 -> user10
|
||||||
|
#
|
||||||
|
# main_user <- user3 <- user11
|
||||||
|
# <- user12
|
||||||
|
# <- user4 <- user13
|
||||||
|
# <- user14
|
||||||
|
# <- user15 <- user16
|
||||||
|
# <- user5
|
||||||
|
|
||||||
|
cls.main_user = baker.make(User)
|
||||||
|
cls.users = baker.make(User, _quantity=17)
|
||||||
|
cls.main_user.godfathers.add(*cls.users[0:3])
|
||||||
|
cls.main_user.godchildren.add(*cls.users[3:6])
|
||||||
|
cls.users[1].godfathers.add(cls.users[6])
|
||||||
|
cls.users[6].godfathers.add(cls.users[7])
|
||||||
|
cls.users[7].godfathers.add(cls.users[8])
|
||||||
|
cls.users[8].godfathers.add(cls.users[9])
|
||||||
|
cls.users[2].godfathers.add(cls.users[10])
|
||||||
|
|
||||||
|
cls.users[3].godchildren.add(cls.users[11], cls.users[12])
|
||||||
|
cls.users[4].godchildren.add(*cls.users[13:16])
|
||||||
|
cls.users[15].godchildren.add(cls.users[16])
|
||||||
|
|
||||||
|
cls.root_user = baker.make(User, is_superuser=True)
|
||||||
|
cls.subscriber_user = subscriber_user.make()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.maxDiff = None
|
||||||
|
|
||||||
|
def test_fetch_family_forbidden(self):
|
||||||
|
# Anonymous user
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("api:family_graph", args=[self.main_user.id])
|
||||||
|
)
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
self.client.force_login(baker.make(User)) # unsubscribed user
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("api:family_graph", args=[self.main_user.id])
|
||||||
|
)
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
def test_fetch_family_hidden_user(self):
|
||||||
|
self.main_user.is_subscriber_viewable = False
|
||||||
|
self.main_user.save()
|
||||||
|
for user_to_login, error_code in [
|
||||||
|
(self.main_user, 200),
|
||||||
|
(self.subscriber_user, 403),
|
||||||
|
(self.root_user, 200),
|
||||||
|
]:
|
||||||
|
self.client.force_login(user_to_login)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("api:family_graph", args=[self.main_user.id])
|
||||||
|
)
|
||||||
|
assert response.status_code == error_code
|
||||||
|
|
||||||
|
def test_fetch_family_with_zero_depth(self):
|
||||||
|
"""Fetch the family with a depth of 0."""
|
||||||
|
self.client.force_login(self.main_user)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("api:family_graph", args=[self.main_user.id])
|
||||||
|
+ f"?godfathers_depth=0&godchildren_depth=0"
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert [u["id"] for u in response.json()["users"]] == [self.main_user.id]
|
||||||
|
assert response.json()["relationships"] == []
|
||||||
|
|
||||||
|
def test_fetch_empty_family(self):
|
||||||
|
empty_user = baker.make(User)
|
||||||
|
self.client.force_login(empty_user)
|
||||||
|
response = self.client.get(reverse("api:family_graph", args=[empty_user.id]))
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert [u["id"] for u in response.json()["users"]] == [empty_user.id]
|
||||||
|
assert response.json()["relationships"] == []
|
||||||
|
|
||||||
|
def test_fetch_whole_family(self):
|
||||||
|
self.client.force_login(self.main_user)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("api:family_graph", args=[self.main_user.id])
|
||||||
|
+ f"?godfathers_depth=10&godchildren_depth=10"
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert [u["id"] for u in response.json()["users"]] == [
|
||||||
|
self.main_user.id,
|
||||||
|
*[u.id for u in self.users],
|
||||||
|
]
|
||||||
|
self.assertCountEqual(
|
||||||
|
response.json()["relationships"],
|
||||||
|
[
|
||||||
|
{"godfather": self.users[0].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.users[1].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.users[2].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.main_user.id, "godchild": self.users[3].id},
|
||||||
|
{"godfather": self.main_user.id, "godchild": self.users[4].id},
|
||||||
|
{"godfather": self.main_user.id, "godchild": self.users[5].id},
|
||||||
|
{"godfather": self.users[6].id, "godchild": self.users[1].id},
|
||||||
|
{"godfather": self.users[7].id, "godchild": self.users[6].id},
|
||||||
|
{"godfather": self.users[8].id, "godchild": self.users[7].id},
|
||||||
|
{"godfather": self.users[9].id, "godchild": self.users[8].id},
|
||||||
|
{"godfather": self.users[10].id, "godchild": self.users[2].id},
|
||||||
|
{"godfather": self.users[3].id, "godchild": self.users[11].id},
|
||||||
|
{"godfather": self.users[3].id, "godchild": self.users[12].id},
|
||||||
|
{"godfather": self.users[4].id, "godchild": self.users[13].id},
|
||||||
|
{"godfather": self.users[4].id, "godchild": self.users[14].id},
|
||||||
|
{"godfather": self.users[4].id, "godchild": self.users[15].id},
|
||||||
|
{"godfather": self.users[15].id, "godchild": self.users[16].id},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_fetch_family_first_level(self):
|
||||||
|
"""Fetch only the first level of the family."""
|
||||||
|
self.client.force_login(self.main_user)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("api:family_graph", args=[self.main_user.id])
|
||||||
|
+ f"?godfathers_depth=1&godchildren_depth=1"
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert [u["id"] for u in response.json()["users"]] == [
|
||||||
|
self.main_user.id,
|
||||||
|
*[u.id for u in self.users[:6]],
|
||||||
|
]
|
||||||
|
self.assertCountEqual(
|
||||||
|
response.json()["relationships"],
|
||||||
|
[
|
||||||
|
{"godfather": self.users[0].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.users[1].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.users[2].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.main_user.id, "godchild": self.users[3].id},
|
||||||
|
{"godfather": self.main_user.id, "godchild": self.users[4].id},
|
||||||
|
{"godfather": self.main_user.id, "godchild": self.users[5].id},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_fetch_family_only_godfathers(self):
|
||||||
|
"""Fetch only the godfathers."""
|
||||||
|
self.client.force_login(self.main_user)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("api:family_graph", args=[self.main_user.id])
|
||||||
|
+ f"?godfathers_depth=10&godchildren_depth=0"
|
||||||
|
)
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert [u["id"] for u in response.json()["users"]] == [
|
||||||
|
self.main_user.id,
|
||||||
|
*[u.id for u in self.users[:3]],
|
||||||
|
*[u.id for u in self.users[6:11]],
|
||||||
|
]
|
||||||
|
self.assertCountEqual(
|
||||||
|
response.json()["relationships"],
|
||||||
|
[
|
||||||
|
{"godfather": self.users[0].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.users[1].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.users[2].id, "godchild": self.main_user.id},
|
||||||
|
{"godfather": self.users[6].id, "godchild": self.users[1].id},
|
||||||
|
{"godfather": self.users[7].id, "godchild": self.users[6].id},
|
||||||
|
{"godfather": self.users[8].id, "godchild": self.users[7].id},
|
||||||
|
{"godfather": self.users[9].id, "godchild": self.users[8].id},
|
||||||
|
{"godfather": self.users[10].id, "godchild": self.users[2].id},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_nb_queries(self):
|
||||||
|
# The number of queries should be 1 per level of existing depth.
|
||||||
|
with self.assertNumQueries(0):
|
||||||
|
self.main_user.get_family(godfathers_depth=0, godchildren_depth=0)
|
||||||
|
with self.assertNumQueries(3):
|
||||||
|
self.main_user.get_family(godfathers_depth=3, godchildren_depth=0)
|
||||||
|
with self.assertNumQueries(3):
|
||||||
|
self.main_user.get_family(godfathers_depth=0, godchildren_depth=3)
|
||||||
|
with self.assertNumQueries(6):
|
||||||
|
self.main_user.get_family(godfathers_depth=3, godchildren_depth=3)
|
||||||
|
with self.assertNumQueries(4):
|
||||||
|
# If a level is empty, the next ones should not be queried.
|
||||||
|
self.main_user.get_family(godfathers_depth=0, godchildren_depth=10)
|
@ -112,11 +112,6 @@ urlpatterns = [
|
|||||||
UserGodfathersTreeView.as_view(),
|
UserGodfathersTreeView.as_view(),
|
||||||
name="user_godfathers_tree",
|
name="user_godfathers_tree",
|
||||||
),
|
),
|
||||||
path(
|
|
||||||
"user/<int:user_id>/godfathers/tree/pict/",
|
|
||||||
UserGodfathersTreePictureView.as_view(),
|
|
||||||
name="user_godfathers_tree_pict",
|
|
||||||
),
|
|
||||||
path(
|
path(
|
||||||
"user/<int:user_id>/godfathers/<int:godfather_id>/<bool:is_father>/delete/",
|
"user/<int:user_id>/godfathers/<int:godfather_id>/<bool:is_father>/delete/",
|
||||||
delete_user_godfather,
|
delete_user_godfather,
|
||||||
|
@ -335,9 +335,40 @@ class UserGodfathersForm(forms.Form):
|
|||||||
label=_("Add"),
|
label=_("Add"),
|
||||||
)
|
)
|
||||||
user = AutoCompleteSelectField(
|
user = AutoCompleteSelectField(
|
||||||
"users", required=True, label=_("Select user"), help_text=None
|
"users", required=True, label=_("Select user"), help_text=""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, user: User, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.target_user = user
|
||||||
|
|
||||||
|
def clean_user(self):
|
||||||
|
other_user = self.cleaned_data.get("user")
|
||||||
|
if not other_user:
|
||||||
|
raise ValidationError(_("This user does not exist"))
|
||||||
|
if other_user == self.target_user:
|
||||||
|
raise ValidationError(_("You cannot be related to yourself"))
|
||||||
|
return other_user
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
if not self.is_valid():
|
||||||
|
return self.cleaned_data
|
||||||
|
other_user = self.cleaned_data["user"]
|
||||||
|
if self.cleaned_data["type"] == "godfather":
|
||||||
|
if self.target_user.godfathers.contains(other_user):
|
||||||
|
self.add_error(
|
||||||
|
"user",
|
||||||
|
_("%s is already your godfather") % (other_user.get_short_name()),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if self.target_user.godchildren.contains(other_user):
|
||||||
|
self.add_error(
|
||||||
|
"user",
|
||||||
|
_("%s is already your godchild") % (other_user.get_short_name()),
|
||||||
|
)
|
||||||
|
return self.cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class PagePropForm(forms.ModelForm):
|
class PagePropForm(forms.ModelForm):
|
||||||
error_css_class = "error"
|
error_css_class = "error"
|
||||||
|
@ -34,7 +34,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
|||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.forms import CheckboxSelectMultiple
|
from django.forms import CheckboxSelectMultiple
|
||||||
from django.forms.models import modelform_factory
|
from django.forms.models import modelform_factory
|
||||||
from django.http import Http404, HttpResponse
|
from django.http import Http404
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
@ -323,7 +323,7 @@ def delete_user_godfather(request, user_id, godfather_id, is_father):
|
|||||||
return redirect("core:user_godfathers", user_id=user_id)
|
return redirect("core:user_godfathers", user_id=user_id)
|
||||||
|
|
||||||
|
|
||||||
class UserGodfathersView(UserTabsMixin, CanViewMixin, DetailView):
|
class UserGodfathersView(UserTabsMixin, CanViewMixin, DetailView, FormView):
|
||||||
"""Display a user's godfathers."""
|
"""Display a user's godfathers."""
|
||||||
|
|
||||||
model = User
|
model = User
|
||||||
@ -331,27 +331,23 @@ class UserGodfathersView(UserTabsMixin, CanViewMixin, DetailView):
|
|||||||
context_object_name = "profile"
|
context_object_name = "profile"
|
||||||
template_name = "core/user_godfathers.jinja"
|
template_name = "core/user_godfathers.jinja"
|
||||||
current_tab = "godfathers"
|
current_tab = "godfathers"
|
||||||
|
form_class = UserGodfathersForm
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def get_form_kwargs(self):
|
||||||
self.object = self.get_object()
|
return super().get_form_kwargs() | {"user": self.object}
|
||||||
self.form = UserGodfathersForm(request.POST)
|
|
||||||
if self.form.is_valid() and self.form.cleaned_data["user"] != self.object:
|
def form_valid(self, form):
|
||||||
if self.form.cleaned_data["type"] == "godfather":
|
if form.cleaned_data["type"] == "godfather":
|
||||||
self.object.godfathers.add(self.form.cleaned_data["user"])
|
self.object.godfathers.add(form.cleaned_data["user"])
|
||||||
self.object.save()
|
else:
|
||||||
else:
|
self.object.godchildren.add(form.cleaned_data["user"])
|
||||||
self.object.godchildren.add(self.form.cleaned_data["user"])
|
return redirect("core:user_godfathers", user_id=self.object.id)
|
||||||
self.object.save()
|
|
||||||
self.form = UserGodfathersForm()
|
|
||||||
return super().get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs) | {
|
||||||
try:
|
"godfathers": list(self.object.godfathers.select_related("profile_pict")),
|
||||||
kwargs["form"] = self.form
|
"godchildren": list(self.object.godchildren.select_related("profile_pict")),
|
||||||
except:
|
}
|
||||||
kwargs["form"] = UserGodfathersForm()
|
|
||||||
return kwargs
|
|
||||||
|
|
||||||
|
|
||||||
class UserGodfathersTreeView(UserTabsMixin, CanViewMixin, DetailView):
|
class UserGodfathersTreeView(UserTabsMixin, CanViewMixin, DetailView):
|
||||||
@ -365,86 +361,12 @@ class UserGodfathersTreeView(UserTabsMixin, CanViewMixin, DetailView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super().get_context_data(**kwargs)
|
kwargs = super().get_context_data(**kwargs)
|
||||||
if "descent" in self.request.GET:
|
kwargs["api_url"] = reverse(
|
||||||
kwargs["param"] = "godchildren"
|
"api:family_graph", kwargs={"user_id": self.object.id}
|
||||||
else:
|
)
|
||||||
kwargs["param"] = "godfathers"
|
|
||||||
kwargs["members_set"] = set()
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
class UserGodfathersTreePictureView(CanViewMixin, DetailView):
|
|
||||||
"""Display a user's tree as a picture."""
|
|
||||||
|
|
||||||
model = User
|
|
||||||
pk_url_kwarg = "user_id"
|
|
||||||
|
|
||||||
def build_complex_graph(self):
|
|
||||||
import pygraphviz as pgv
|
|
||||||
|
|
||||||
self.depth = int(self.request.GET.get("depth", 4))
|
|
||||||
if self.param == "godfathers":
|
|
||||||
self.graph = pgv.AGraph(strict=False, directed=True, rankdir="BT")
|
|
||||||
else:
|
|
||||||
self.graph = pgv.AGraph(strict=False, directed=True)
|
|
||||||
family = set()
|
|
||||||
self.level = 1
|
|
||||||
|
|
||||||
# Since the tree isn't very deep, we can build it recursively
|
|
||||||
def crawl_family(user):
|
|
||||||
if self.level > self.depth:
|
|
||||||
return
|
|
||||||
self.level += 1
|
|
||||||
for u in user.__getattribute__(self.param).all():
|
|
||||||
self.graph.add_edge(user.get_short_name(), u.get_short_name())
|
|
||||||
if u not in family:
|
|
||||||
family.add(u)
|
|
||||||
crawl_family(u)
|
|
||||||
self.level -= 1
|
|
||||||
|
|
||||||
self.graph.add_node(self.object.get_short_name())
|
|
||||||
family.add(self.object)
|
|
||||||
crawl_family(self.object)
|
|
||||||
|
|
||||||
def build_family_graph(self):
|
|
||||||
import pygraphviz as pgv
|
|
||||||
|
|
||||||
self.graph = pgv.AGraph(strict=False, directed=True)
|
|
||||||
self.graph.add_node(self.object.get_short_name())
|
|
||||||
for u in self.object.godfathers.all():
|
|
||||||
self.graph.add_edge(u.get_short_name(), self.object.get_short_name())
|
|
||||||
for u in self.object.godchildren.all():
|
|
||||||
self.graph.add_edge(self.object.get_short_name(), u.get_short_name())
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
self.object = self.get_object()
|
|
||||||
if "descent" in self.request.GET:
|
|
||||||
self.param = "godchildren"
|
|
||||||
elif "ancestors" in self.request.GET:
|
|
||||||
self.param = "godfathers"
|
|
||||||
else:
|
|
||||||
self.param = "family"
|
|
||||||
|
|
||||||
if self.param == "family":
|
|
||||||
self.build_family_graph()
|
|
||||||
else:
|
|
||||||
self.build_complex_graph()
|
|
||||||
# Pimp the graph before display
|
|
||||||
self.graph.node_attr["color"] = "lightblue"
|
|
||||||
self.graph.node_attr["style"] = "filled"
|
|
||||||
main_node = self.graph.get_node(self.object.get_short_name())
|
|
||||||
main_node.attr["color"] = "sandybrown"
|
|
||||||
main_node.attr["shape"] = "rect"
|
|
||||||
if self.param == "godchildren":
|
|
||||||
self.graph.graph_attr["label"] = _("Godchildren")
|
|
||||||
elif self.param == "godfathers":
|
|
||||||
self.graph.graph_attr["label"] = _("Family")
|
|
||||||
else:
|
|
||||||
self.graph.graph_attr["label"] = _("Family")
|
|
||||||
img = self.graph.draw(format="png", prog="dot")
|
|
||||||
return HttpResponse(img, content_type="image/png")
|
|
||||||
|
|
||||||
|
|
||||||
class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
|
class UserStatsView(UserTabsMixin, CanViewMixin, DetailView):
|
||||||
"""Display a user's stats."""
|
"""Display a user's stats."""
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ Il faut d'abord générer un fichier de traductions,
|
|||||||
l'éditer et enfin le compiler au format binaire pour qu'il soit lu par le serveur.
|
l'éditer et enfin le compiler au format binaire pour qu'il soit lu par le serveur.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./manage.py makemessages --locale=fr --ignore "env/*" -e py,jinja
|
./manage.py makemessages --locale=fr -e py,jinja # Pour le backend
|
||||||
|
./manage.py makemessages --locale=fr -d djangojs # Pour le frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
## Éditer le fichier django.po
|
## Éditer le fichier django.po
|
||||||
|
@ -8,7 +8,6 @@ Certaines dépendances sont nécessaires niveau système :
|
|||||||
- zlib1g-dev
|
- zlib1g-dev
|
||||||
- python
|
- python
|
||||||
- gettext
|
- gettext
|
||||||
- graphviz
|
|
||||||
|
|
||||||
### Installer WSL
|
### Installer WSL
|
||||||
|
|
||||||
@ -71,8 +70,8 @@ cd /mnt/<la_lettre_du_disque>/vos/fichiers/comme/dhab
|
|||||||
Puis installez les autres dépendances :
|
Puis installez les autres dépendances :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt install build-essentials libssl-dev libjpeg-dev zlib1g-dev python-dev \
|
sudo apt install build-essential libssl-dev libjpeg-dev zlib1g-dev python-dev \
|
||||||
libffi-dev python-dev-is-python3 libgraphviz-dev pkg-config \
|
libffi-dev python-dev-is-python3 pkg-config \
|
||||||
gettext git pipx
|
gettext git pipx
|
||||||
|
|
||||||
pipx install poetry
|
pipx install poetry
|
||||||
@ -85,7 +84,7 @@ cd /mnt/<la_lettre_du_disque>/vos/fichiers/comme/dhab
|
|||||||
|
|
||||||
sudo pacman -S python
|
sudo pacman -S python
|
||||||
|
|
||||||
sudo pacman -S gcc git graphviz gettext graphviz pkgconf python-poetry
|
sudo pacman -S gcc git gettext pkgconf python-poetry
|
||||||
```
|
```
|
||||||
|
|
||||||
=== "macOS"
|
=== "macOS"
|
||||||
@ -94,11 +93,7 @@ cd /mnt/<la_lettre_du_disque>/vos/fichiers/comme/dhab
|
|||||||
Il est également nécessaire d'avoir installé xcode
|
Il est également nécessaire d'avoir installé xcode
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo 'export PATH="$(brew --prefix graphviz)/bin:$PATH"' >> ~/.zshrc
|
brew install git python pipx
|
||||||
echo 'export CFLAGS="-isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -I $(brew --prefix graphviz)/include"' >> ~/.zshrc
|
|
||||||
echo 'export LDFLAGS="-L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -L $(brew --prefix graphviz)/lib"' >> ~/.zshrc
|
|
||||||
|
|
||||||
brew install git python graphviz pipx
|
|
||||||
pipx install poetry
|
pipx install poetry
|
||||||
|
|
||||||
# Pour bien configurer gettext
|
# Pour bien configurer gettext
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-09-08 13:30+0200\n"
|
"POT-Creation-Date: 2024-09-17 11:24+0200\n"
|
||||||
"PO-Revision-Date: 2016-07-18\n"
|
"PO-Revision-Date: 2016-07-18\n"
|
||||||
"Last-Translator: Skia <skia@libskia.so>\n"
|
"Last-Translator: Skia <skia@libskia.so>\n"
|
||||||
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
||||||
@ -41,7 +41,7 @@ msgstr "code postal"
|
|||||||
msgid "country"
|
msgid "country"
|
||||||
msgstr "pays"
|
msgstr "pays"
|
||||||
|
|
||||||
#: accounting/models.py:55 core/models.py:364
|
#: accounting/models.py:55 core/models.py:365
|
||||||
msgid "phone"
|
msgid "phone"
|
||||||
msgstr "téléphone"
|
msgstr "téléphone"
|
||||||
|
|
||||||
@ -127,8 +127,8 @@ msgstr "numéro"
|
|||||||
msgid "journal"
|
msgid "journal"
|
||||||
msgstr "classeur"
|
msgstr "classeur"
|
||||||
|
|
||||||
#: accounting/models.py:261 core/models.py:904 core/models.py:1431
|
#: accounting/models.py:261 core/models.py:940 core/models.py:1467
|
||||||
#: core/models.py:1476 core/models.py:1505 core/models.py:1529
|
#: core/models.py:1512 core/models.py:1541 core/models.py:1565
|
||||||
#: counter/models.py:585 counter/models.py:678 counter/models.py:888
|
#: counter/models.py:585 counter/models.py:678 counter/models.py:888
|
||||||
#: eboutic/models.py:57 eboutic/models.py:173 forum/models.py:311
|
#: eboutic/models.py:57 eboutic/models.py:173 forum/models.py:311
|
||||||
#: forum/models.py:412 stock/models.py:96
|
#: forum/models.py:412 stock/models.py:96
|
||||||
@ -166,7 +166,7 @@ msgid "accounting type"
|
|||||||
msgstr "type comptable"
|
msgstr "type comptable"
|
||||||
|
|
||||||
#: accounting/models.py:299 accounting/models.py:438 accounting/models.py:471
|
#: accounting/models.py:299 accounting/models.py:438 accounting/models.py:471
|
||||||
#: accounting/models.py:503 core/models.py:1504 core/models.py:1530
|
#: accounting/models.py:503 core/models.py:1540 core/models.py:1566
|
||||||
#: counter/models.py:644
|
#: counter/models.py:644
|
||||||
msgid "label"
|
msgid "label"
|
||||||
msgstr "étiquette"
|
msgstr "étiquette"
|
||||||
@ -219,7 +219,7 @@ msgstr "Compte"
|
|||||||
msgid "Company"
|
msgid "Company"
|
||||||
msgstr "Entreprise"
|
msgstr "Entreprise"
|
||||||
|
|
||||||
#: accounting/models.py:312 core/models.py:311 sith/settings.py:413
|
#: accounting/models.py:312 core/models.py:312 sith/settings.py:413
|
||||||
#: stock/templates/stock/shopping_list_items.jinja:37
|
#: stock/templates/stock/shopping_list_items.jinja:37
|
||||||
msgid "Other"
|
msgid "Other"
|
||||||
msgstr "Autre"
|
msgstr "Autre"
|
||||||
@ -780,7 +780,8 @@ msgstr "Opération liée : "
|
|||||||
#: core/templates/core/file_edit.jinja:8
|
#: core/templates/core/file_edit.jinja:8
|
||||||
#: core/templates/core/macros_pages.jinja:25
|
#: core/templates/core/macros_pages.jinja:25
|
||||||
#: core/templates/core/page_prop.jinja:11
|
#: core/templates/core/page_prop.jinja:11
|
||||||
#: core/templates/core/user_godfathers.jinja:62
|
#: core/templates/core/user_godfathers.jinja:61
|
||||||
|
#: core/templates/core/user_godfathers_tree.jinja:91
|
||||||
#: core/templates/core/user_preferences.jinja:18
|
#: core/templates/core/user_preferences.jinja:18
|
||||||
#: core/templates/core/user_preferences.jinja:27
|
#: core/templates/core/user_preferences.jinja:27
|
||||||
#: core/templates/core/user_preferences.jinja:65
|
#: core/templates/core/user_preferences.jinja:65
|
||||||
@ -1041,11 +1042,11 @@ msgstr "actif"
|
|||||||
msgid "short description"
|
msgid "short description"
|
||||||
msgstr "description courte"
|
msgstr "description courte"
|
||||||
|
|
||||||
#: club/models.py:80 core/models.py:366
|
#: club/models.py:80 core/models.py:367
|
||||||
msgid "address"
|
msgid "address"
|
||||||
msgstr "Adresse"
|
msgstr "Adresse"
|
||||||
|
|
||||||
#: club/models.py:97 core/models.py:277
|
#: club/models.py:97 core/models.py:278
|
||||||
msgid "home"
|
msgid "home"
|
||||||
msgstr "home"
|
msgstr "home"
|
||||||
|
|
||||||
@ -1064,12 +1065,12 @@ msgstr "Un club avec ce nom UNIX existe déjà."
|
|||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr "nom d'utilisateur"
|
msgstr "nom d'utilisateur"
|
||||||
|
|
||||||
#: club/models.py:353 core/models.py:330 election/models.py:178
|
#: club/models.py:353 core/models.py:331 election/models.py:178
|
||||||
#: election/models.py:212 trombi/models.py:211
|
#: election/models.py:212 trombi/models.py:211
|
||||||
msgid "role"
|
msgid "role"
|
||||||
msgstr "rôle"
|
msgstr "rôle"
|
||||||
|
|
||||||
#: club/models.py:358 core/models.py:88 counter/models.py:209
|
#: club/models.py:358 core/models.py:89 counter/models.py:209
|
||||||
#: counter/models.py:240 election/models.py:13 election/models.py:115
|
#: counter/models.py:240 election/models.py:13 election/models.py:115
|
||||||
#: election/models.py:188 forum/models.py:60 forum/models.py:244
|
#: election/models.py:188 forum/models.py:60 forum/models.py:244
|
||||||
msgid "description"
|
msgid "description"
|
||||||
@ -1084,7 +1085,7 @@ msgid "Enter a valid address. Only the root of the address is needed."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Entrez une adresse valide. Seule la racine de l'adresse est nécessaire."
|
"Entrez une adresse valide. Seule la racine de l'adresse est nécessaire."
|
||||||
|
|
||||||
#: club/models.py:428 com/models.py:82 com/models.py:309 core/models.py:905
|
#: club/models.py:428 com/models.py:82 com/models.py:309 core/models.py:941
|
||||||
msgid "is moderated"
|
msgid "is moderated"
|
||||||
msgstr "est modéré"
|
msgstr "est modéré"
|
||||||
|
|
||||||
@ -1439,7 +1440,7 @@ msgstr "résumé"
|
|||||||
msgid "content"
|
msgid "content"
|
||||||
msgstr "contenu"
|
msgstr "contenu"
|
||||||
|
|
||||||
#: com/models.py:71 core/models.py:1474 launderette/models.py:92
|
#: com/models.py:71 core/models.py:1510 launderette/models.py:92
|
||||||
#: launderette/models.py:130 launderette/models.py:181 stock/models.py:74
|
#: launderette/models.py:130 launderette/models.py:181 stock/models.py:74
|
||||||
#: stock/models.py:129
|
#: stock/models.py:129
|
||||||
msgid "type"
|
msgid "type"
|
||||||
@ -1490,7 +1491,7 @@ msgstr "weekmail"
|
|||||||
msgid "rank"
|
msgid "rank"
|
||||||
msgstr "rang"
|
msgstr "rang"
|
||||||
|
|
||||||
#: com/models.py:295 core/models.py:870 core/models.py:920
|
#: com/models.py:295 core/models.py:906 core/models.py:956
|
||||||
msgid "file"
|
msgid "file"
|
||||||
msgstr "fichier"
|
msgstr "fichier"
|
||||||
|
|
||||||
@ -1975,30 +1976,30 @@ msgstr ""
|
|||||||
"Vous devez êtres un membre du bureau du club sélectionné pour poster dans le "
|
"Vous devez êtres un membre du bureau du club sélectionné pour poster dans le "
|
||||||
"Weekmail."
|
"Weekmail."
|
||||||
|
|
||||||
#: core/models.py:83
|
#: core/models.py:84
|
||||||
msgid "meta group status"
|
msgid "meta group status"
|
||||||
msgstr "status du meta-groupe"
|
msgstr "status du meta-groupe"
|
||||||
|
|
||||||
#: core/models.py:85
|
#: core/models.py:86
|
||||||
msgid "Whether a group is a meta group or not"
|
msgid "Whether a group is a meta group or not"
|
||||||
msgstr "Si un groupe est un meta-groupe ou pas"
|
msgstr "Si un groupe est un meta-groupe ou pas"
|
||||||
|
|
||||||
#: core/models.py:171
|
#: core/models.py:172
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(value)s is not a valid promo (between 0 and %(end)s)"
|
msgid "%(value)s is not a valid promo (between 0 and %(end)s)"
|
||||||
msgstr "%(value)s n'est pas une promo valide (doit être entre 0 et %(end)s)"
|
msgstr "%(value)s n'est pas une promo valide (doit être entre 0 et %(end)s)"
|
||||||
|
|
||||||
#: core/models.py:230
|
#: core/models.py:231
|
||||||
msgid "username"
|
msgid "username"
|
||||||
msgstr "nom d'utilisateur"
|
msgstr "nom d'utilisateur"
|
||||||
|
|
||||||
#: core/models.py:234
|
#: core/models.py:235
|
||||||
msgid "Required. 254 characters or fewer. Letters, digits and ./+/-/_ only."
|
msgid "Required. 254 characters or fewer. Letters, digits and ./+/-/_ only."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Requis. Pas plus de 254 caractères. Uniquement des lettres, numéros, et ./"
|
"Requis. Pas plus de 254 caractères. Uniquement des lettres, numéros, et ./"
|
||||||
"+/-/_"
|
"+/-/_"
|
||||||
|
|
||||||
#: core/models.py:240
|
#: core/models.py:241
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter a valid username. This value may contain only letters, numbers and ./"
|
"Enter a valid username. This value may contain only letters, numbers and ./"
|
||||||
"+/-/_ characters."
|
"+/-/_ characters."
|
||||||
@ -2006,43 +2007,43 @@ msgstr ""
|
|||||||
"Entrez un nom d'utilisateur correct. Uniquement des lettres, numéros, et ./"
|
"Entrez un nom d'utilisateur correct. Uniquement des lettres, numéros, et ./"
|
||||||
"+/-/_"
|
"+/-/_"
|
||||||
|
|
||||||
#: core/models.py:246
|
#: core/models.py:247
|
||||||
msgid "A user with that username already exists."
|
msgid "A user with that username already exists."
|
||||||
msgstr "Un utilisateur de ce nom existe déjà"
|
msgstr "Un utilisateur de ce nom existe déjà"
|
||||||
|
|
||||||
#: core/models.py:248
|
#: core/models.py:249
|
||||||
msgid "first name"
|
msgid "first name"
|
||||||
msgstr "Prénom"
|
msgstr "Prénom"
|
||||||
|
|
||||||
#: core/models.py:249
|
#: core/models.py:250
|
||||||
msgid "last name"
|
msgid "last name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#: core/models.py:250
|
#: core/models.py:251
|
||||||
msgid "email address"
|
msgid "email address"
|
||||||
msgstr "adresse email"
|
msgstr "adresse email"
|
||||||
|
|
||||||
#: core/models.py:251
|
#: core/models.py:252
|
||||||
msgid "date of birth"
|
msgid "date of birth"
|
||||||
msgstr "date de naissance"
|
msgstr "date de naissance"
|
||||||
|
|
||||||
#: core/models.py:252
|
#: core/models.py:253
|
||||||
msgid "nick name"
|
msgid "nick name"
|
||||||
msgstr "surnom"
|
msgstr "surnom"
|
||||||
|
|
||||||
#: core/models.py:254
|
#: core/models.py:255
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr "status \"staff\""
|
msgstr "status \"staff\""
|
||||||
|
|
||||||
#: core/models.py:256
|
#: core/models.py:257
|
||||||
msgid "Designates whether the user can log into this admin site."
|
msgid "Designates whether the user can log into this admin site."
|
||||||
msgstr "Est-ce que l'utilisateur peut se logger à la partie admin du site."
|
msgstr "Est-ce que l'utilisateur peut se logger à la partie admin du site."
|
||||||
|
|
||||||
#: core/models.py:259
|
#: core/models.py:260
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "actif"
|
msgstr "actif"
|
||||||
|
|
||||||
#: core/models.py:262
|
#: core/models.py:263
|
||||||
msgid ""
|
msgid ""
|
||||||
"Designates whether this user should be treated as active. Unselect this "
|
"Designates whether this user should be treated as active. Unselect this "
|
||||||
"instead of deleting accounts."
|
"instead of deleting accounts."
|
||||||
@ -2050,163 +2051,163 @@ msgstr ""
|
|||||||
"Est-ce que l'utilisateur doit être traité comme actif. Désélectionnez au "
|
"Est-ce que l'utilisateur doit être traité comme actif. Désélectionnez au "
|
||||||
"lieu de supprimer les comptes."
|
"lieu de supprimer les comptes."
|
||||||
|
|
||||||
#: core/models.py:266
|
#: core/models.py:267
|
||||||
msgid "date joined"
|
msgid "date joined"
|
||||||
msgstr "date d'inscription"
|
msgstr "date d'inscription"
|
||||||
|
|
||||||
#: core/models.py:267
|
#: core/models.py:268
|
||||||
msgid "last update"
|
msgid "last update"
|
||||||
msgstr "dernière mise à jour"
|
msgstr "dernière mise à jour"
|
||||||
|
|
||||||
#: core/models.py:269
|
#: core/models.py:270
|
||||||
msgid "superuser"
|
msgid "superuser"
|
||||||
msgstr "super-utilisateur"
|
msgstr "super-utilisateur"
|
||||||
|
|
||||||
#: core/models.py:271
|
#: core/models.py:272
|
||||||
msgid "Designates whether this user is a superuser. "
|
msgid "Designates whether this user is a superuser. "
|
||||||
msgstr "Est-ce que l'utilisateur est super-utilisateur."
|
msgstr "Est-ce que l'utilisateur est super-utilisateur."
|
||||||
|
|
||||||
#: core/models.py:285
|
#: core/models.py:286
|
||||||
msgid "profile"
|
msgid "profile"
|
||||||
msgstr "profil"
|
msgstr "profil"
|
||||||
|
|
||||||
#: core/models.py:293
|
#: core/models.py:294
|
||||||
msgid "avatar"
|
msgid "avatar"
|
||||||
msgstr "avatar"
|
msgstr "avatar"
|
||||||
|
|
||||||
#: core/models.py:301
|
#: core/models.py:302
|
||||||
msgid "scrub"
|
msgid "scrub"
|
||||||
msgstr "blouse"
|
msgstr "blouse"
|
||||||
|
|
||||||
#: core/models.py:307
|
#: core/models.py:308
|
||||||
msgid "sex"
|
msgid "sex"
|
||||||
msgstr "Genre"
|
msgstr "Genre"
|
||||||
|
|
||||||
#: core/models.py:311
|
#: core/models.py:312
|
||||||
msgid "Man"
|
msgid "Man"
|
||||||
msgstr "Homme"
|
msgstr "Homme"
|
||||||
|
|
||||||
#: core/models.py:311
|
#: core/models.py:312
|
||||||
msgid "Woman"
|
msgid "Woman"
|
||||||
msgstr "Femme"
|
msgstr "Femme"
|
||||||
|
|
||||||
#: core/models.py:313
|
#: core/models.py:314
|
||||||
msgid "pronouns"
|
msgid "pronouns"
|
||||||
msgstr "pronoms"
|
msgstr "pronoms"
|
||||||
|
|
||||||
#: core/models.py:315
|
#: core/models.py:316
|
||||||
msgid "tshirt size"
|
msgid "tshirt size"
|
||||||
msgstr "taille de t-shirt"
|
msgstr "taille de t-shirt"
|
||||||
|
|
||||||
#: core/models.py:318
|
#: core/models.py:319
|
||||||
msgid "-"
|
msgid "-"
|
||||||
msgstr "-"
|
msgstr "-"
|
||||||
|
|
||||||
#: core/models.py:319
|
#: core/models.py:320
|
||||||
msgid "XS"
|
msgid "XS"
|
||||||
msgstr "XS"
|
msgstr "XS"
|
||||||
|
|
||||||
#: core/models.py:320
|
#: core/models.py:321
|
||||||
msgid "S"
|
msgid "S"
|
||||||
msgstr "S"
|
msgstr "S"
|
||||||
|
|
||||||
#: core/models.py:321
|
#: core/models.py:322
|
||||||
msgid "M"
|
msgid "M"
|
||||||
msgstr "M"
|
msgstr "M"
|
||||||
|
|
||||||
#: core/models.py:322
|
#: core/models.py:323
|
||||||
msgid "L"
|
msgid "L"
|
||||||
msgstr "L"
|
msgstr "L"
|
||||||
|
|
||||||
#: core/models.py:323
|
#: core/models.py:324
|
||||||
msgid "XL"
|
msgid "XL"
|
||||||
msgstr "XL"
|
msgstr "XL"
|
||||||
|
|
||||||
#: core/models.py:324
|
#: core/models.py:325
|
||||||
msgid "XXL"
|
msgid "XXL"
|
||||||
msgstr "XXL"
|
msgstr "XXL"
|
||||||
|
|
||||||
#: core/models.py:325
|
#: core/models.py:326
|
||||||
msgid "XXXL"
|
msgid "XXXL"
|
||||||
msgstr "XXXL"
|
msgstr "XXXL"
|
||||||
|
|
||||||
#: core/models.py:333
|
#: core/models.py:334
|
||||||
msgid "Student"
|
msgid "Student"
|
||||||
msgstr "Étudiant"
|
msgstr "Étudiant"
|
||||||
|
|
||||||
#: core/models.py:334
|
#: core/models.py:335
|
||||||
msgid "Administrative agent"
|
msgid "Administrative agent"
|
||||||
msgstr "Personnel administratif"
|
msgstr "Personnel administratif"
|
||||||
|
|
||||||
#: core/models.py:335
|
#: core/models.py:336
|
||||||
msgid "Teacher"
|
msgid "Teacher"
|
||||||
msgstr "Enseignant"
|
msgstr "Enseignant"
|
||||||
|
|
||||||
#: core/models.py:336
|
#: core/models.py:337
|
||||||
msgid "Agent"
|
msgid "Agent"
|
||||||
msgstr "Personnel"
|
msgstr "Personnel"
|
||||||
|
|
||||||
#: core/models.py:337
|
#: core/models.py:338
|
||||||
msgid "Doctor"
|
msgid "Doctor"
|
||||||
msgstr "Doctorant"
|
msgstr "Doctorant"
|
||||||
|
|
||||||
#: core/models.py:338
|
#: core/models.py:339
|
||||||
msgid "Former student"
|
msgid "Former student"
|
||||||
msgstr "Ancien étudiant"
|
msgstr "Ancien étudiant"
|
||||||
|
|
||||||
#: core/models.py:339
|
#: core/models.py:340
|
||||||
msgid "Service"
|
msgid "Service"
|
||||||
msgstr "Service"
|
msgstr "Service"
|
||||||
|
|
||||||
#: core/models.py:345
|
#: core/models.py:346
|
||||||
msgid "department"
|
msgid "department"
|
||||||
msgstr "département"
|
msgstr "département"
|
||||||
|
|
||||||
#: core/models.py:352
|
#: core/models.py:353
|
||||||
msgid "dpt option"
|
msgid "dpt option"
|
||||||
msgstr "Filière"
|
msgstr "Filière"
|
||||||
|
|
||||||
#: core/models.py:354 pedagogy/models.py:69 pedagogy/models.py:293
|
#: core/models.py:355 pedagogy/models.py:69 pedagogy/models.py:293
|
||||||
msgid "semester"
|
msgid "semester"
|
||||||
msgstr "semestre"
|
msgstr "semestre"
|
||||||
|
|
||||||
#: core/models.py:355
|
#: core/models.py:356
|
||||||
msgid "quote"
|
msgid "quote"
|
||||||
msgstr "citation"
|
msgstr "citation"
|
||||||
|
|
||||||
#: core/models.py:356
|
#: core/models.py:357
|
||||||
msgid "school"
|
msgid "school"
|
||||||
msgstr "école"
|
msgstr "école"
|
||||||
|
|
||||||
#: core/models.py:358
|
#: core/models.py:359
|
||||||
msgid "promo"
|
msgid "promo"
|
||||||
msgstr "promo"
|
msgstr "promo"
|
||||||
|
|
||||||
#: core/models.py:361
|
#: core/models.py:362
|
||||||
msgid "forum signature"
|
msgid "forum signature"
|
||||||
msgstr "signature du forum"
|
msgstr "signature du forum"
|
||||||
|
|
||||||
#: core/models.py:363
|
#: core/models.py:364
|
||||||
msgid "second email address"
|
msgid "second email address"
|
||||||
msgstr "adresse email secondaire"
|
msgstr "adresse email secondaire"
|
||||||
|
|
||||||
#: core/models.py:365
|
#: core/models.py:366
|
||||||
msgid "parent phone"
|
msgid "parent phone"
|
||||||
msgstr "téléphone des parents"
|
msgstr "téléphone des parents"
|
||||||
|
|
||||||
#: core/models.py:368
|
#: core/models.py:369
|
||||||
msgid "parent address"
|
msgid "parent address"
|
||||||
msgstr "adresse des parents"
|
msgstr "adresse des parents"
|
||||||
|
|
||||||
#: core/models.py:371
|
#: core/models.py:372
|
||||||
msgid "is subscriber viewable"
|
msgid "is subscriber viewable"
|
||||||
msgstr "profil visible par les cotisants"
|
msgstr "profil visible par les cotisants"
|
||||||
|
|
||||||
#: core/models.py:571
|
#: core/models.py:572
|
||||||
msgid "A user with that username already exists"
|
msgid "A user with that username already exists"
|
||||||
msgstr "Un utilisateur de ce nom d'utilisateur existe déjà"
|
msgstr "Un utilisateur de ce nom d'utilisateur existe déjà"
|
||||||
|
|
||||||
#: core/models.py:701 core/templates/core/macros.jinja:75
|
#: core/models.py:737 core/templates/core/macros.jinja:75
|
||||||
#: core/templates/core/macros.jinja:77 core/templates/core/macros.jinja:78
|
#: core/templates/core/macros.jinja:77 core/templates/core/macros.jinja:78
|
||||||
#: core/templates/core/user_detail.jinja:100
|
#: core/templates/core/user_detail.jinja:100
|
||||||
#: core/templates/core/user_detail.jinja:101
|
#: core/templates/core/user_detail.jinja:101
|
||||||
@ -2225,101 +2226,101 @@ msgstr "Un utilisateur de ce nom d'utilisateur existe déjà"
|
|||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Profil"
|
msgstr "Profil"
|
||||||
|
|
||||||
#: core/models.py:820
|
#: core/models.py:856
|
||||||
msgid "Visitor"
|
msgid "Visitor"
|
||||||
msgstr "Visiteur"
|
msgstr "Visiteur"
|
||||||
|
|
||||||
#: core/models.py:827
|
#: core/models.py:863
|
||||||
msgid "receive the Weekmail"
|
msgid "receive the Weekmail"
|
||||||
msgstr "recevoir le Weekmail"
|
msgstr "recevoir le Weekmail"
|
||||||
|
|
||||||
#: core/models.py:828
|
#: core/models.py:864
|
||||||
msgid "show your stats to others"
|
msgid "show your stats to others"
|
||||||
msgstr "montrez vos statistiques aux autres"
|
msgstr "montrez vos statistiques aux autres"
|
||||||
|
|
||||||
#: core/models.py:830
|
#: core/models.py:866
|
||||||
msgid "get a notification for every click"
|
msgid "get a notification for every click"
|
||||||
msgstr "avoir une notification pour chaque click"
|
msgstr "avoir une notification pour chaque click"
|
||||||
|
|
||||||
#: core/models.py:833
|
#: core/models.py:869
|
||||||
msgid "get a notification for every refilling"
|
msgid "get a notification for every refilling"
|
||||||
msgstr "avoir une notification pour chaque rechargement"
|
msgstr "avoir une notification pour chaque rechargement"
|
||||||
|
|
||||||
#: core/models.py:859 sas/views.py:356
|
#: core/models.py:895 sas/views.py:356
|
||||||
msgid "file name"
|
msgid "file name"
|
||||||
msgstr "nom du fichier"
|
msgstr "nom du fichier"
|
||||||
|
|
||||||
#: core/models.py:863 core/models.py:1223
|
#: core/models.py:899 core/models.py:1259
|
||||||
msgid "parent"
|
msgid "parent"
|
||||||
msgstr "parent"
|
msgstr "parent"
|
||||||
|
|
||||||
#: core/models.py:877
|
#: core/models.py:913
|
||||||
msgid "compressed file"
|
msgid "compressed file"
|
||||||
msgstr "version allégée"
|
msgstr "version allégée"
|
||||||
|
|
||||||
#: core/models.py:884
|
#: core/models.py:920
|
||||||
msgid "thumbnail"
|
msgid "thumbnail"
|
||||||
msgstr "miniature"
|
msgstr "miniature"
|
||||||
|
|
||||||
#: core/models.py:892 core/models.py:909
|
#: core/models.py:928 core/models.py:945
|
||||||
msgid "owner"
|
msgid "owner"
|
||||||
msgstr "propriétaire"
|
msgstr "propriétaire"
|
||||||
|
|
||||||
#: core/models.py:896 core/models.py:1240 core/views/files.py:230
|
#: core/models.py:932 core/models.py:1276 core/views/files.py:230
|
||||||
msgid "edit group"
|
msgid "edit group"
|
||||||
msgstr "groupe d'édition"
|
msgstr "groupe d'édition"
|
||||||
|
|
||||||
#: core/models.py:899 core/models.py:1243 core/views/files.py:233
|
#: core/models.py:935 core/models.py:1279 core/views/files.py:233
|
||||||
msgid "view group"
|
msgid "view group"
|
||||||
msgstr "groupe de vue"
|
msgstr "groupe de vue"
|
||||||
|
|
||||||
#: core/models.py:901
|
#: core/models.py:937
|
||||||
msgid "is folder"
|
msgid "is folder"
|
||||||
msgstr "est un dossier"
|
msgstr "est un dossier"
|
||||||
|
|
||||||
#: core/models.py:902
|
#: core/models.py:938
|
||||||
msgid "mime type"
|
msgid "mime type"
|
||||||
msgstr "type mime"
|
msgstr "type mime"
|
||||||
|
|
||||||
#: core/models.py:903
|
#: core/models.py:939
|
||||||
msgid "size"
|
msgid "size"
|
||||||
msgstr "taille"
|
msgstr "taille"
|
||||||
|
|
||||||
#: core/models.py:914
|
#: core/models.py:950
|
||||||
msgid "asked for removal"
|
msgid "asked for removal"
|
||||||
msgstr "retrait demandé"
|
msgstr "retrait demandé"
|
||||||
|
|
||||||
#: core/models.py:916
|
#: core/models.py:952
|
||||||
msgid "is in the SAS"
|
msgid "is in the SAS"
|
||||||
msgstr "est dans le SAS"
|
msgstr "est dans le SAS"
|
||||||
|
|
||||||
#: core/models.py:1010
|
#: core/models.py:1046
|
||||||
msgid "Character '/' not authorized in name"
|
msgid "Character '/' not authorized in name"
|
||||||
msgstr "Le caractère '/' n'est pas autorisé dans les noms de fichier"
|
msgstr "Le caractère '/' n'est pas autorisé dans les noms de fichier"
|
||||||
|
|
||||||
#: core/models.py:1012 core/models.py:1016
|
#: core/models.py:1048 core/models.py:1052
|
||||||
msgid "Loop in folder tree"
|
msgid "Loop in folder tree"
|
||||||
msgstr "Boucle dans l'arborescence des dossiers"
|
msgstr "Boucle dans l'arborescence des dossiers"
|
||||||
|
|
||||||
#: core/models.py:1019
|
#: core/models.py:1055
|
||||||
msgid "You can not make a file be a children of a non folder file"
|
msgid "You can not make a file be a children of a non folder file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous ne pouvez pas mettre un fichier enfant de quelque chose qui n'est pas "
|
"Vous ne pouvez pas mettre un fichier enfant de quelque chose qui n'est pas "
|
||||||
"un dossier"
|
"un dossier"
|
||||||
|
|
||||||
#: core/models.py:1030
|
#: core/models.py:1066
|
||||||
msgid "Duplicate file"
|
msgid "Duplicate file"
|
||||||
msgstr "Un fichier de ce nom existe déjà"
|
msgstr "Un fichier de ce nom existe déjà"
|
||||||
|
|
||||||
#: core/models.py:1047
|
#: core/models.py:1083
|
||||||
msgid "You must provide a file"
|
msgid "You must provide a file"
|
||||||
msgstr "Vous devez fournir un fichier"
|
msgstr "Vous devez fournir un fichier"
|
||||||
|
|
||||||
#: core/models.py:1206
|
#: core/models.py:1242
|
||||||
msgid "page unix name"
|
msgid "page unix name"
|
||||||
msgstr "nom unix de la page"
|
msgstr "nom unix de la page"
|
||||||
|
|
||||||
#: core/models.py:1212
|
#: core/models.py:1248
|
||||||
msgid ""
|
msgid ""
|
||||||
"Enter a valid page name. This value may contain only unaccented letters, "
|
"Enter a valid page name. This value may contain only unaccented letters, "
|
||||||
"numbers and ./+/-/_ characters."
|
"numbers and ./+/-/_ characters."
|
||||||
@ -2327,55 +2328,55 @@ msgstr ""
|
|||||||
"Entrez un nom de page correct. Uniquement des lettres non accentuées, "
|
"Entrez un nom de page correct. Uniquement des lettres non accentuées, "
|
||||||
"numéros, et ./+/-/_"
|
"numéros, et ./+/-/_"
|
||||||
|
|
||||||
#: core/models.py:1230
|
#: core/models.py:1266
|
||||||
msgid "page name"
|
msgid "page name"
|
||||||
msgstr "nom de la page"
|
msgstr "nom de la page"
|
||||||
|
|
||||||
#: core/models.py:1235
|
#: core/models.py:1271
|
||||||
msgid "owner group"
|
msgid "owner group"
|
||||||
msgstr "groupe propriétaire"
|
msgstr "groupe propriétaire"
|
||||||
|
|
||||||
#: core/models.py:1248
|
#: core/models.py:1284
|
||||||
msgid "lock user"
|
msgid "lock user"
|
||||||
msgstr "utilisateur bloquant"
|
msgstr "utilisateur bloquant"
|
||||||
|
|
||||||
#: core/models.py:1255
|
#: core/models.py:1291
|
||||||
msgid "lock_timeout"
|
msgid "lock_timeout"
|
||||||
msgstr "décompte du déblocage"
|
msgstr "décompte du déblocage"
|
||||||
|
|
||||||
#: core/models.py:1305
|
#: core/models.py:1341
|
||||||
msgid "Duplicate page"
|
msgid "Duplicate page"
|
||||||
msgstr "Une page de ce nom existe déjà"
|
msgstr "Une page de ce nom existe déjà"
|
||||||
|
|
||||||
#: core/models.py:1308
|
#: core/models.py:1344
|
||||||
msgid "Loop in page tree"
|
msgid "Loop in page tree"
|
||||||
msgstr "Boucle dans l'arborescence des pages"
|
msgstr "Boucle dans l'arborescence des pages"
|
||||||
|
|
||||||
#: core/models.py:1428
|
#: core/models.py:1464
|
||||||
msgid "revision"
|
msgid "revision"
|
||||||
msgstr "révision"
|
msgstr "révision"
|
||||||
|
|
||||||
#: core/models.py:1429
|
#: core/models.py:1465
|
||||||
msgid "page title"
|
msgid "page title"
|
||||||
msgstr "titre de la page"
|
msgstr "titre de la page"
|
||||||
|
|
||||||
#: core/models.py:1430
|
#: core/models.py:1466
|
||||||
msgid "page content"
|
msgid "page content"
|
||||||
msgstr "contenu de la page"
|
msgstr "contenu de la page"
|
||||||
|
|
||||||
#: core/models.py:1471
|
#: core/models.py:1507
|
||||||
msgid "url"
|
msgid "url"
|
||||||
msgstr "url"
|
msgstr "url"
|
||||||
|
|
||||||
#: core/models.py:1472
|
#: core/models.py:1508
|
||||||
msgid "param"
|
msgid "param"
|
||||||
msgstr "param"
|
msgstr "param"
|
||||||
|
|
||||||
#: core/models.py:1477
|
#: core/models.py:1513
|
||||||
msgid "viewed"
|
msgid "viewed"
|
||||||
msgstr "vue"
|
msgstr "vue"
|
||||||
|
|
||||||
#: core/models.py:1535
|
#: core/models.py:1571
|
||||||
msgid "operation type"
|
msgid "operation type"
|
||||||
msgstr "type d'opération"
|
msgstr "type d'opération"
|
||||||
|
|
||||||
@ -2906,8 +2907,9 @@ msgstr "Vous avez correctement changé votre mot de passe !"
|
|||||||
|
|
||||||
#: core/templates/core/password_reset.jinja:8
|
#: core/templates/core/password_reset.jinja:8
|
||||||
#: core/templates/core/password_reset_confirm.jinja:8
|
#: core/templates/core/password_reset_confirm.jinja:8
|
||||||
|
#: core/templates/core/user_godfathers_tree.jinja:87
|
||||||
msgid "Reset"
|
msgid "Reset"
|
||||||
msgstr "Reset"
|
msgstr "Réinitialiser"
|
||||||
|
|
||||||
#: core/templates/core/password_reset_complete.jinja:4
|
#: core/templates/core/password_reset_complete.jinja:4
|
||||||
msgid "You successfully reset your password!"
|
msgid "You successfully reset your password!"
|
||||||
@ -3223,68 +3225,44 @@ msgstr "Numéro de compte : "
|
|||||||
msgid "%(user_name)s's family"
|
msgid "%(user_name)s's family"
|
||||||
msgstr "Famille de %(user_name)s"
|
msgstr "Famille de %(user_name)s"
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers.jinja:15
|
#: core/templates/core/user_godfathers.jinja:20
|
||||||
msgid "Show family picture"
|
msgid "Show family tree"
|
||||||
msgstr "Voir une image de la famille"
|
msgstr "Afficher l'arbre généalogique"
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers.jinja:18
|
#: core/templates/core/user_godfathers.jinja:24
|
||||||
msgid "Godfathers / Godmothers"
|
msgid "Godfathers / Godmothers"
|
||||||
msgstr "Parrains / Marraines"
|
msgstr "Parrains / Marraines"
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers.jinja:32
|
#: core/templates/core/user_godfathers.jinja:38
|
||||||
msgid "Show ancestors tree"
|
|
||||||
msgstr "Voir l'arbre des ancêtres"
|
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers.jinja:35
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:50
|
|
||||||
msgid "No godfathers / godmothers"
|
msgid "No godfathers / godmothers"
|
||||||
msgstr "Pas de famille"
|
msgstr "Pas de famille"
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers.jinja:38 core/views/user.py:439
|
#: core/templates/core/user_godfathers.jinja:41
|
||||||
msgid "Godchildren"
|
msgid "Godchildren"
|
||||||
msgstr "Fillots / Fillotes"
|
msgstr "Fillots / Fillotes"
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers.jinja:52
|
#: core/templates/core/user_godfathers.jinja:54
|
||||||
msgid "Show descent tree"
|
|
||||||
msgstr "Voir l'arbre de la descendance"
|
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers.jinja:55
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:48
|
|
||||||
msgid "No godchildren"
|
msgid "No godchildren"
|
||||||
msgstr "Pas de fillots / fillotes"
|
msgstr "Pas de fillots / fillotes"
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:5
|
|
||||||
#, python-format
|
|
||||||
msgid "%(user_name)s's godchildren"
|
|
||||||
msgstr "Fillots/Fillotes de %(user_name)s"
|
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:7
|
|
||||||
#, python-format
|
|
||||||
msgid "%(user_name)s's godfathers"
|
|
||||||
msgstr "Parrains/Marraines de %(user_name)s"
|
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:20
|
#: core/templates/core/user_godfathers_tree.jinja:20
|
||||||
msgid "Already seen (check above)"
|
|
||||||
msgstr "Déjà vu (voir plus haut)"
|
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:33
|
|
||||||
msgid "Back to family"
|
|
||||||
msgstr "Retour à la famille"
|
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:37
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:41
|
|
||||||
msgid "Show a picture of the tree"
|
|
||||||
msgstr "Voir une image de l'arbre"
|
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:38
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Descent tree of %(u)s"
|
msgid "%(user_name)s's family tree"
|
||||||
msgstr "Descendants de %(u)s"
|
msgstr "Arbre généalogique de %(user_name)s"
|
||||||
|
|
||||||
#: core/templates/core/user_godfathers_tree.jinja:42
|
#: core/templates/core/user_godfathers_tree.jinja:29
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Ancestors tree of %(u)s"
|
msgid "Max godfather depth between %(min)s and %(max)s"
|
||||||
msgstr "Ancêtres de %(u)s"
|
msgstr "Maximum de profondeur pour les parrains entre %(min)s et %(max)s"
|
||||||
|
|
||||||
|
#: core/templates/core/user_godfathers_tree.jinja:55
|
||||||
|
#, python-format
|
||||||
|
msgid "Max godchildren depth between %(min)s and %(max)s"
|
||||||
|
msgstr "Maximum de profondeur pour les fillots entre %(min)s et %(max)s"
|
||||||
|
|
||||||
|
#: core/templates/core/user_godfathers_tree.jinja:83
|
||||||
|
msgid "Reverse"
|
||||||
|
msgstr "Inverser"
|
||||||
|
|
||||||
#: core/templates/core/user_group.jinja:9
|
#: core/templates/core/user_group.jinja:9
|
||||||
#, python-format
|
#, python-format
|
||||||
@ -3680,12 +3658,31 @@ msgstr "Fillot / Fillote"
|
|||||||
msgid "Select user"
|
msgid "Select user"
|
||||||
msgstr "Choisir un utilisateur"
|
msgstr "Choisir un utilisateur"
|
||||||
|
|
||||||
#: core/views/forms.py:351 core/views/forms.py:369 election/models.py:22
|
#: core/views/forms.py:348
|
||||||
|
msgid "This user does not exist"
|
||||||
|
msgstr "Cet utilisateur n'existe pas"
|
||||||
|
|
||||||
|
#: core/views/forms.py:350
|
||||||
|
msgid "You cannot be related to yourself"
|
||||||
|
msgstr "Vous ne pouvez pas être relié à vous-même"
|
||||||
|
|
||||||
|
#: core/views/forms.py:362
|
||||||
|
#, python-format
|
||||||
|
msgid "%s is already your godfather"
|
||||||
|
msgstr "%s est déjà votre parrain/marraine"
|
||||||
|
|
||||||
|
#: core/views/forms.py:368
|
||||||
|
#, fuzzy, python-format
|
||||||
|
#| msgid "This user has already commented on this UV"
|
||||||
|
msgid "%s is already your godchild"
|
||||||
|
msgstr "%s est déjà votre fillot/fillote"
|
||||||
|
|
||||||
|
#: core/views/forms.py:382 core/views/forms.py:400 election/models.py:22
|
||||||
#: election/views.py:147
|
#: election/views.py:147
|
||||||
msgid "edit groups"
|
msgid "edit groups"
|
||||||
msgstr "groupe d'édition"
|
msgstr "groupe d'édition"
|
||||||
|
|
||||||
#: core/views/forms.py:354 core/views/forms.py:372 election/models.py:29
|
#: core/views/forms.py:385 core/views/forms.py:403 election/models.py:29
|
||||||
#: election/views.py:150
|
#: election/views.py:150
|
||||||
msgid "view groups"
|
msgid "view groups"
|
||||||
msgstr "groupe de vue"
|
msgstr "groupe de vue"
|
||||||
@ -3702,7 +3699,7 @@ msgstr "Utilisateurs à ajouter au groupe"
|
|||||||
msgid "We couldn't verify that this email actually exists"
|
msgid "We couldn't verify that this email actually exists"
|
||||||
msgstr "Nous n'avons pas réussi à vérifier que cette adresse mail existe."
|
msgstr "Nous n'avons pas réussi à vérifier que cette adresse mail existe."
|
||||||
|
|
||||||
#: core/views/user.py:202 core/views/user.py:441 core/views/user.py:443
|
#: core/views/user.py:202
|
||||||
msgid "Family"
|
msgid "Family"
|
||||||
msgstr "Famille"
|
msgstr "Famille"
|
||||||
|
|
||||||
@ -6313,85 +6310,3 @@ msgstr "Vous ne pouvez plus écrire de commentaires, la date est passée."
|
|||||||
#, python-format
|
#, python-format
|
||||||
msgid "Maximum characters: %(max_length)s"
|
msgid "Maximum characters: %(max_length)s"
|
||||||
msgstr "Nombre de caractères max: %(max_length)s"
|
msgstr "Nombre de caractères max: %(max_length)s"
|
||||||
|
|
||||||
#~ msgid "Picture Unavailable"
|
|
||||||
#~ msgstr "Photo Indisponible"
|
|
||||||
|
|
||||||
#~ msgid "Convert dokuwiki/BBcode syntax to Markdown"
|
|
||||||
#~ msgstr "Convertir de la syntaxe dokuwiki/BBcode vers Markdown"
|
|
||||||
|
|
||||||
#~ msgid "This album does not contain any photos."
|
|
||||||
#~ msgstr "Cet album ne contient aucune photo."
|
|
||||||
|
|
||||||
#~ msgid "You have no basket."
|
|
||||||
#~ msgstr "Vous n'avez pas de panier."
|
|
||||||
|
|
||||||
#~ msgid "The basket cookie was badly formatted."
|
|
||||||
#~ msgstr "Le cookie du panier a été mal formaté."
|
|
||||||
|
|
||||||
#, python-format
|
|
||||||
#~ msgid "%(name)s : this product does not exist."
|
|
||||||
#~ msgstr "%(name)s : ce produit n'existe pas."
|
|
||||||
|
|
||||||
#, python-format
|
|
||||||
#~ msgid "You cannot buy %(nbr)d %(name)s."
|
|
||||||
#~ msgstr "Vous ne pouvez pas acheter %(nbr)d %(name)s."
|
|
||||||
|
|
||||||
#~ msgid "Error downloading your pictures"
|
|
||||||
#~ msgstr "Erreur de téléchargement de vos photos"
|
|
||||||
|
|
||||||
#~ msgid "Error connecting to the server"
|
|
||||||
#~ msgstr "Erreur lors de la connection au serveur"
|
|
||||||
|
|
||||||
#~ msgid "past member"
|
|
||||||
#~ msgstr "Anciens membres"
|
|
||||||
|
|
||||||
#, python-format
|
|
||||||
#~ msgid "Welcome %(user_name)s!"
|
|
||||||
#~ msgstr "Bienvenue, %(user_name)s!"
|
|
||||||
|
|
||||||
#~ msgid ""
|
|
||||||
#~ "You successfully registered and you will soon receive a confirmation mail."
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "Vous vous êtes correctement enregistré, et vous devriez recevoir "
|
|
||||||
#~ "rapidement un email de confirmation."
|
|
||||||
|
|
||||||
#, python-format
|
|
||||||
#~ msgid "Your username is %(username)s."
|
|
||||||
#~ msgstr "Votre nom d'utilisateur est %(username)s."
|
|
||||||
|
|
||||||
#~ msgid "Subscription error"
|
|
||||||
#~ msgstr "Erreur de cotisation"
|
|
||||||
|
|
||||||
#~ msgid "Folder: "
|
|
||||||
#~ msgstr "Dossier : "
|
|
||||||
|
|
||||||
#~ msgid "File: "
|
|
||||||
#~ msgstr "Fichier : "
|
|
||||||
|
|
||||||
#~ msgid "Username"
|
|
||||||
#~ msgstr "Nom d'utilisateur"
|
|
||||||
|
|
||||||
#~ msgid "Password"
|
|
||||||
#~ msgstr "Mot de passe"
|
|
||||||
|
|
||||||
#~ msgid "Register a user"
|
|
||||||
#~ msgstr "Enregistrer un utilisateur"
|
|
||||||
|
|
||||||
#~ msgid "Current profile: "
|
|
||||||
#~ msgstr "Profil actuel : "
|
|
||||||
|
|
||||||
#~ msgid "Current avatar: "
|
|
||||||
#~ msgstr "Avatar actuel : "
|
|
||||||
|
|
||||||
#~ msgid "Current scrub: "
|
|
||||||
#~ msgstr "Blouse actuelle : "
|
|
||||||
|
|
||||||
#~ msgid "preview"
|
|
||||||
#~ msgstr "miniature"
|
|
||||||
|
|
||||||
#~ msgid "Rotate left"
|
|
||||||
#~ msgstr "Tourner vers la gauche"
|
|
||||||
|
|
||||||
#~ msgid "Rotate right"
|
|
||||||
#~ msgstr "Tourner vers la droite"
|
|
||||||
|
21
locale/fr/LC_MESSAGES/djangojs.po
Normal file
21
locale/fr/LC_MESSAGES/djangojs.po
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Sith AE french frontend translation file
|
||||||
|
# Copyright (C) 2024
|
||||||
|
# This file is distributed under the same license as the Sith package.
|
||||||
|
# ae@utbm.fr / ae.info@utbm.fr
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2024-09-17 11:54+0200\n"
|
||||||
|
"PO-Revision-Date: 2024-09-17 11:54+0200\n"
|
||||||
|
"Last-Translator: Sli <antoine@bartuccio.fr>\n"
|
||||||
|
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
#: core/static/user/js/family_graph.js:230
|
||||||
|
msgid "family_tree.%(extension)s"
|
||||||
|
msgstr "arbre_genealogique.%(extension)s"
|
513
poetry.lock
generated
513
poetry.lock
generated
@ -92,78 +92,78 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cffi"
|
name = "cffi"
|
||||||
version = "1.17.0"
|
version = "1.17.1"
|
||||||
description = "Foreign Function Interface for Python calling C code."
|
description = "Foreign Function Interface for Python calling C code."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"},
|
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"},
|
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"},
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"},
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"},
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"},
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"},
|
{file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"},
|
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"},
|
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"},
|
{file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"},
|
{file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
|
||||||
{file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"},
|
{file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"},
|
{file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"},
|
{file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"},
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"},
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"},
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"},
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"},
|
{file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"},
|
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"},
|
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"},
|
{file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"},
|
{file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
|
||||||
{file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"},
|
{file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"},
|
{file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"},
|
{file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"},
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"},
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"},
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"},
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"},
|
{file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"},
|
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"},
|
{file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"},
|
{file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
|
||||||
{file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"},
|
{file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"},
|
{file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"},
|
{file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"},
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"},
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"},
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"},
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"},
|
{file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"},
|
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"},
|
{file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"},
|
{file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
|
||||||
{file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"},
|
{file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"},
|
{file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"},
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"},
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"},
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"},
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"},
|
{file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"},
|
{file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
|
||||||
{file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"},
|
{file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"},
|
{file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"},
|
{file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"},
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"},
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"},
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"},
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"},
|
{file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"},
|
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"},
|
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"},
|
{file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"},
|
{file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
|
||||||
{file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"},
|
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
|
||||||
{file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"},
|
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -412,38 +412,38 @@ toml = ["tomli"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cryptography"
|
name = "cryptography"
|
||||||
version = "43.0.0"
|
version = "43.0.1"
|
||||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"},
|
{file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"},
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"},
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"},
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"},
|
{file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"},
|
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"},
|
{file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"},
|
{file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"},
|
||||||
{file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"},
|
{file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"},
|
{file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"},
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"},
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"},
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"},
|
{file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"},
|
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"},
|
{file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"},
|
{file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"},
|
||||||
{file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"},
|
{file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"},
|
||||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"},
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"},
|
||||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"},
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"},
|
||||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"},
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"},
|
||||||
{file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"},
|
{file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"},
|
||||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"},
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"},
|
||||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"},
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"},
|
||||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"},
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"},
|
||||||
{file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"},
|
{file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"},
|
||||||
{file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"},
|
{file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -456,7 +456,7 @@ nox = ["nox"]
|
|||||||
pep8test = ["check-sdist", "click", "mypy", "ruff"]
|
pep8test = ["check-sdist", "click", "mypy", "ruff"]
|
||||||
sdist = ["build"]
|
sdist = ["build"]
|
||||||
ssh = ["bcrypt (>=3.1.5)"]
|
ssh = ["bcrypt (>=3.1.5)"]
|
||||||
test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
|
||||||
test-randomorder = ["pytest-randomly"]
|
test-randomorder = ["pytest-randomly"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -497,13 +497,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "django"
|
name = "django"
|
||||||
version = "4.2.15"
|
version = "4.2.16"
|
||||||
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "Django-4.2.15-py3-none-any.whl", hash = "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30"},
|
{file = "Django-4.2.16-py3-none-any.whl", hash = "sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898"},
|
||||||
{file = "Django-4.2.15.tar.gz", hash = "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a"},
|
{file = "Django-4.2.16.tar.gz", hash = "sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -761,19 +761,19 @@ python-dateutil = ">=2.4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filelock"
|
name = "filelock"
|
||||||
version = "3.15.4"
|
version = "3.16.0"
|
||||||
description = "A platform independent file lock."
|
description = "A platform independent file lock."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"},
|
{file = "filelock-3.16.0-py3-none-any.whl", hash = "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609"},
|
||||||
{file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"},
|
{file = "filelock-3.16.0.tar.gz", hash = "sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
|
||||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"]
|
testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.1.1)", "pytest (>=8.3.2)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.3)"]
|
||||||
typing = ["typing-extensions (>=4.8)"]
|
typing = ["typing-extensions (>=4.12.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "freezegun"
|
name = "freezegun"
|
||||||
@ -1450,13 +1450,13 @@ ptyprocess = ">=0.5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phonenumbers"
|
name = "phonenumbers"
|
||||||
version = "8.13.44"
|
version = "8.13.45"
|
||||||
description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
|
description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
files = [
|
files = [
|
||||||
{file = "phonenumbers-8.13.44-py2.py3-none-any.whl", hash = "sha256:52cd02865dab1428ca9e89d442629b61d407c7dc687cfb80a3e8d068a584513c"},
|
{file = "phonenumbers-8.13.45-py2.py3-none-any.whl", hash = "sha256:bf05ec20fcd13f0d53e43a34ed7bd1c8be26a72b88fce4b8c64fca5b4641987a"},
|
||||||
{file = "phonenumbers-8.13.44.tar.gz", hash = "sha256:2175021e84ee4e41b43c890f2d0af51f18c6ca9ad525886d6d6e4ea882e46fac"},
|
{file = "phonenumbers-8.13.45.tar.gz", hash = "sha256:53679a95b6060fd5e15467759252c87933d8566d6a5be00995a579eb0e02435b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1558,19 +1558,19 @@ xmp = ["defusedxml"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "4.2.2"
|
version = "4.3.2"
|
||||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
|
{file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"},
|
||||||
{file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
|
{file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"]
|
||||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
|
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"]
|
||||||
type = ["mypy (>=1.8)"]
|
type = ["mypy (>=1.11.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pluggy"
|
name = "pluggy"
|
||||||
@ -1691,18 +1691,18 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.8.2"
|
version = "2.9.1"
|
||||||
description = "Data validation using Python type hints"
|
description = "Data validation using Python type hints"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"},
|
{file = "pydantic-2.9.1-py3-none-any.whl", hash = "sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612"},
|
||||||
{file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"},
|
{file = "pydantic-2.9.1.tar.gz", hash = "sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
annotated-types = ">=0.4.0"
|
annotated-types = ">=0.6.0"
|
||||||
pydantic-core = "2.20.1"
|
pydantic-core = "2.23.3"
|
||||||
typing-extensions = [
|
typing-extensions = [
|
||||||
{version = ">=4.12.2", markers = "python_version >= \"3.13\""},
|
{version = ">=4.12.2", markers = "python_version >= \"3.13\""},
|
||||||
{version = ">=4.6.1", markers = "python_version < \"3.13\""},
|
{version = ">=4.6.1", markers = "python_version < \"3.13\""},
|
||||||
@ -1710,103 +1710,104 @@ typing-extensions = [
|
|||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
email = ["email-validator (>=2.0.0)"]
|
email = ["email-validator (>=2.0.0)"]
|
||||||
|
timezone = ["tzdata"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic-core"
|
name = "pydantic-core"
|
||||||
version = "2.20.1"
|
version = "2.23.3"
|
||||||
description = "Core functionality for Pydantic validation and serialization"
|
description = "Core functionality for Pydantic validation and serialization"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"},
|
{file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"},
|
{file = "pydantic_core-2.23.3-cp310-none-win32.whl", hash = "sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b"},
|
||||||
{file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"},
|
{file = "pydantic_core-2.23.3-cp310-none-win_amd64.whl", hash = "sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"},
|
{file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"},
|
{file = "pydantic_core-2.23.3-cp311-none-win32.whl", hash = "sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1"},
|
||||||
{file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"},
|
{file = "pydantic_core-2.23.3-cp311-none-win_amd64.whl", hash = "sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"},
|
{file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"},
|
{file = "pydantic_core-2.23.3-cp312-none-win32.whl", hash = "sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c"},
|
||||||
{file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"},
|
{file = "pydantic_core-2.23.3-cp312-none-win_amd64.whl", hash = "sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"},
|
{file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"},
|
{file = "pydantic_core-2.23.3-cp313-none-win32.whl", hash = "sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8"},
|
||||||
{file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"},
|
{file = "pydantic_core-2.23.3-cp313-none-win_amd64.whl", hash = "sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"},
|
{file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"},
|
{file = "pydantic_core-2.23.3-cp38-none-win32.whl", hash = "sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710"},
|
||||||
{file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"},
|
{file = "pydantic_core-2.23.3-cp38-none-win_amd64.whl", hash = "sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"},
|
{file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"},
|
{file = "pydantic_core-2.23.3-cp39-none-win32.whl", hash = "sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7"},
|
||||||
{file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"},
|
{file = "pydantic_core-2.23.3-cp39-none-win_amd64.whl", hash = "sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4"},
|
||||||
{file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"},
|
{file = "pydantic_core-2.23.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25"},
|
||||||
{file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"},
|
{file = "pydantic_core-2.23.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab"},
|
||||||
{file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"},
|
{file = "pydantic_core-2.23.3.tar.gz", hash = "sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -1826,16 +1827,6 @@ files = [
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
windows-terminal = ["colorama (>=0.4.6)"]
|
windows-terminal = ["colorama (>=0.4.6)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pygraphviz"
|
|
||||||
version = "1.13"
|
|
||||||
description = "Python interface to Graphviz"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.10"
|
|
||||||
files = [
|
|
||||||
{file = "pygraphviz-1.13.tar.gz", hash = "sha256:6ad8aa2f26768830a5a1cfc8a14f022d13df170a8f6fdfd68fd1aa1267000964"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pymdown-extensions"
|
name = "pymdown-extensions"
|
||||||
version = "10.9"
|
version = "10.9"
|
||||||
@ -1894,13 +1885,13 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytest-django"
|
name = "pytest-django"
|
||||||
version = "4.8.0"
|
version = "4.9.0"
|
||||||
description = "A Django plugin for pytest."
|
description = "A Django plugin for pytest."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "pytest-django-4.8.0.tar.gz", hash = "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90"},
|
{file = "pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99"},
|
||||||
{file = "pytest_django-4.8.0-py3-none-any.whl", hash = "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7"},
|
{file = "pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2232,13 +2223,13 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sentry-sdk"
|
name = "sentry-sdk"
|
||||||
version = "2.13.0"
|
version = "2.14.0"
|
||||||
description = "Python client for Sentry (https://sentry.io)"
|
description = "Python client for Sentry (https://sentry.io)"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
{file = "sentry_sdk-2.13.0-py2.py3-none-any.whl", hash = "sha256:6beede8fc2ab4043da7f69d95534e320944690680dd9a963178a49de71d726c6"},
|
{file = "sentry_sdk-2.14.0-py2.py3-none-any.whl", hash = "sha256:b8bc3dc51d06590df1291b7519b85c75e2ced4f28d9ea655b6d54033503b5bf4"},
|
||||||
{file = "sentry_sdk-2.13.0.tar.gz", hash = "sha256:8d4a576f7a98eb2fdb40e13106e41f330e5c79d72a68be1316e7852cf4995260"},
|
{file = "sentry_sdk-2.14.0.tar.gz", hash = "sha256:1e0e2eaf6dad918c7d1e0edac868a7bf20017b177f242cefe2a6bcd47955961d"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2532,13 +2523,13 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "virtualenv"
|
name = "virtualenv"
|
||||||
version = "20.26.3"
|
version = "20.26.4"
|
||||||
description = "Virtual Python Environment builder"
|
description = "Virtual Python Environment builder"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"},
|
{file = "virtualenv-20.26.4-py3-none-any.whl", hash = "sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55"},
|
||||||
{file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"},
|
{file = "virtualenv-20.26.4.tar.gz", hash = "sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
@ -2552,41 +2543,41 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "watchdog"
|
name = "watchdog"
|
||||||
version = "5.0.0"
|
version = "5.0.2"
|
||||||
description = "Filesystem events monitoring"
|
description = "Filesystem events monitoring"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.9"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "watchdog-5.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf3216ec994eabb2212df9861f19056ca0d4cd3516d56cb95801933876519bfe"},
|
{file = "watchdog-5.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d961f4123bb3c447d9fcdcb67e1530c366f10ab3a0c7d1c0c9943050936d4877"},
|
||||||
{file = "watchdog-5.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb59ad83a1700304fc1ac7bc53ae9e5cbe9d60a52ed9bba8e2e2d782a201bb2b"},
|
{file = "watchdog-5.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72990192cb63872c47d5e5fefe230a401b87fd59d257ee577d61c9e5564c62e5"},
|
||||||
{file = "watchdog-5.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1228cb097e855d1798b550be8f0e9f0cfbac4384f9a3e91f66d250d03e11294e"},
|
{file = "watchdog-5.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bec703ad90b35a848e05e1b40bf0050da7ca28ead7ac4be724ae5ac2653a1a0"},
|
||||||
{file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3c177085c3d210d1c73cb4569442bdaef706ebebc423bd7aed9e90fc12b2e553"},
|
{file = "watchdog-5.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae7a1879918f6544201d33666909b040a46421054a50e0f773e0d870ed7438d"},
|
||||||
{file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01ab36cddc836a0f202c66267daaef92ba5c17c7d6436deff0587bb61234c5c9"},
|
{file = "watchdog-5.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4a440f725f3b99133de610bfec93d570b13826f89616377715b9cd60424db6e"},
|
||||||
{file = "watchdog-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0834c21efa3e767849b09e667274604c7cdfe30b49eb95d794565c53f4db3c1e"},
|
{file = "watchdog-5.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8b2918c19e0d48f5f20df458c84692e2a054f02d9df25e6c3c930063eca64c1"},
|
||||||
{file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1e26f570dd7f5178656affb24d6f0e22ce66c8daf88d4061a27bfb9ac866b40d"},
|
{file = "watchdog-5.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:aa9cd6e24126d4afb3752a3e70fce39f92d0e1a58a236ddf6ee823ff7dba28ee"},
|
||||||
{file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d146331e6b206baa9f6dd40f72b5783ad2302c240df68e7fce196d30588ccf7b"},
|
{file = "watchdog-5.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f627c5bf5759fdd90195b0c0431f99cff4867d212a67b384442c51136a098ed7"},
|
||||||
{file = "watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c96b1706430839872a3e33b9370ee3f7a0079f6b828129d88498ad1f96a0f45"},
|
{file = "watchdog-5.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7594a6d32cda2b49df3fd9abf9b37c8d2f3eab5df45c24056b4a671ac661619"},
|
||||||
{file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:663b096368ed7831ac42259919fdb9e0a1f0a8994d972675dfbcca0225e74de1"},
|
{file = "watchdog-5.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba32efcccfe2c58f4d01115440d1672b4eb26cdd6fc5b5818f1fb41f7c3e1889"},
|
||||||
{file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:685931412978d00a91a193d9018fc9e394e565e8e7a0c275512a80e59c6e85f8"},
|
{file = "watchdog-5.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:963f7c4c91e3f51c998eeff1b3fb24a52a8a34da4f956e470f4b068bb47b78ee"},
|
||||||
{file = "watchdog-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:109daafc5b0f2a98d1fa9475ff9737eb3559d57b18129a36495e20c71de0b44f"},
|
{file = "watchdog-5.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8c47150aa12f775e22efff1eee9f0f6beee542a7aa1a985c271b1997d340184f"},
|
||||||
{file = "watchdog-5.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c2b4d90962639ae7cee371ea3a8da506831945d4418eee090c53bc38e6648dc6"},
|
{file = "watchdog-5.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:14dd4ed023d79d1f670aa659f449bcd2733c33a35c8ffd88689d9d243885198b"},
|
||||||
{file = "watchdog-5.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e58eafe9cc5ceebe1562cdb89bacdcd0ef470896e8b0139fe677a5abec243da"},
|
{file = "watchdog-5.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b84bff0391ad4abe25c2740c7aec0e3de316fdf7764007f41e248422a7760a7f"},
|
||||||
{file = "watchdog-5.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8d747bf6d8fe5ce89cb1a36c3724d1599bd4cde3f90fcba518e6260c7058a52"},
|
{file = "watchdog-5.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e8d5ff39f0a9968952cce548e8e08f849141a4fcc1290b1c17c032ba697b9d7"},
|
||||||
{file = "watchdog-5.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bc16d448a74a929b896ed9578c25756b2125400b19b3258be8d9a681c7ae8e71"},
|
{file = "watchdog-5.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fb223456db6e5f7bd9bbd5cd969f05aae82ae21acc00643b60d81c770abd402b"},
|
||||||
{file = "watchdog-5.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7e6b0e9b8a9dc3865d65888b5f5222da4ba9c4e09eab13cff5e305e7b7e7248f"},
|
{file = "watchdog-5.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9814adb768c23727a27792c77812cf4e2fd9853cd280eafa2bcfa62a99e8bd6e"},
|
||||||
{file = "watchdog-5.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4fe6780915000743074236b21b6c37419aea71112af62237881bc265589fe463"},
|
{file = "watchdog-5.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:901ee48c23f70193d1a7bc2d9ee297df66081dd5f46f0ca011be4f70dec80dab"},
|
||||||
{file = "watchdog-5.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0710e9502727f688a7e06d48078545c54485b3d6eb53b171810879d8223c362a"},
|
{file = "watchdog-5.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:638bcca3d5b1885c6ec47be67bf712b00a9ab3d4b22ec0881f4889ad870bc7e8"},
|
||||||
{file = "watchdog-5.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d76efab5248aafbf8a2c2a63cd7b9545e6b346ad1397af8b862a3bb3140787d8"},
|
{file = "watchdog-5.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5597c051587f8757798216f2485e85eac583c3b343e9aa09127a3a6f82c65ee8"},
|
||||||
{file = "watchdog-5.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:ff4e957c45c446de34c513eadce01d0b65da7eee47c01dce472dd136124552c9"},
|
{file = "watchdog-5.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:53ed1bf71fcb8475dd0ef4912ab139c294c87b903724b6f4a8bd98e026862e6d"},
|
||||||
{file = "watchdog-5.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:16c1aa3377bb1f82c5e24277fcbf4e2cac3c4ce46aaaf7212d53caa9076eb7b7"},
|
{file = "watchdog-5.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:29e4a2607bd407d9552c502d38b45a05ec26a8e40cc7e94db9bb48f861fa5abc"},
|
||||||
{file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:22fcad6168fc43cf0e709bd854be5b8edbb0b260f0a6f28f1ea9baa53c6907f7"},
|
{file = "watchdog-5.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:b6dc8f1d770a8280997e4beae7b9a75a33b268c59e033e72c8a10990097e5fde"},
|
||||||
{file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0120b2fa65732797ffa65fa8ee5540c288aa861d91447df298626d6385a24658"},
|
{file = "watchdog-5.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:d2ab34adc9bf1489452965cdb16a924e97d4452fcf88a50b21859068b50b5c3b"},
|
||||||
{file = "watchdog-5.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2aa59fab7ff75281778c649557275ca3085eccbdf825a0e2a5ca3810e977afe5"},
|
{file = "watchdog-5.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:7d1aa7e4bb0f0c65a1a91ba37c10e19dabf7eaaa282c5787e51371f090748f4b"},
|
||||||
{file = "watchdog-5.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:78db0fe0336958fc0e1269545c980b6f33d04d184ba191b2800a8b71d3e971a9"},
|
{file = "watchdog-5.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:726eef8f8c634ac6584f86c9c53353a010d9f311f6c15a034f3800a7a891d941"},
|
||||||
{file = "watchdog-5.0.0-py3-none-win32.whl", hash = "sha256:d1acef802916083f2ad7988efc7decf07e46e266916c0a09d8fb9d387288ea12"},
|
{file = "watchdog-5.0.2-py3-none-win32.whl", hash = "sha256:bda40c57115684d0216556671875e008279dea2dc00fcd3dde126ac8e0d7a2fb"},
|
||||||
{file = "watchdog-5.0.0-py3-none-win_amd64.whl", hash = "sha256:3c2d50fdb86aa6df3973313272f5a17eb26eab29ff5a0bf54b6d34597b4dc4e4"},
|
{file = "watchdog-5.0.2-py3-none-win_amd64.whl", hash = "sha256:d010be060c996db725fbce7e3ef14687cdcc76f4ca0e4339a68cc4532c382a73"},
|
||||||
{file = "watchdog-5.0.0-py3-none-win_ia64.whl", hash = "sha256:1d17ec7e022c34fa7ddc72aa41bf28c9d1207ffb193df18ba4f6fde453725b3c"},
|
{file = "watchdog-5.0.2-py3-none-win_ia64.whl", hash = "sha256:3960136b2b619510569b90f0cd96408591d6c251a75c97690f4553ca88889769"},
|
||||||
{file = "watchdog-5.0.0.tar.gz", hash = "sha256:990aedb9e2f336b45a70aed9c014450e7c4a70fd99c5f5b1834d57e1453a177e"},
|
{file = "watchdog-5.0.2.tar.gz", hash = "sha256:dcebf7e475001d2cdeb020be630dc5b687e9acdd60d16fea6bb4508e7b94cf76"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
@ -2635,4 +2626,4 @@ filelock = ">=3.4"
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.12"
|
python-versions = "^3.12"
|
||||||
content-hash = "0041e2ec8f5a4ff1f0fca78bb0d6c5865d0a12a92b9869940c389fd524569ba2"
|
content-hash = "b6202203d272cecdb607ea8ebc1ba12dd8369e4f387f65692c4a9681915e6f48"
|
||||||
|
@ -39,7 +39,6 @@ django-ordered-model = "^3.7"
|
|||||||
django-simple-captcha = "^0.6.0"
|
django-simple-captcha = "^0.6.0"
|
||||||
python-dateutil = "^2.8.2"
|
python-dateutil = "^2.8.2"
|
||||||
sentry-sdk = "^2.12.0"
|
sentry-sdk = "^2.12.0"
|
||||||
pygraphviz = "^1.1"
|
|
||||||
Jinja2 = "^3.1"
|
Jinja2 = "^3.1"
|
||||||
django-countries = "^7.5.1"
|
django-countries = "^7.5.1"
|
||||||
dict2xml = "^1.7.3"
|
dict2xml = "^1.7.3"
|
||||||
|
@ -751,6 +751,10 @@ SITH_FRONT_DEP_VERSIONS = {
|
|||||||
"https://github.com/getsentry/sentry-javascript/": "8.26.0",
|
"https://github.com/getsentry/sentry-javascript/": "8.26.0",
|
||||||
"https://github.com/jhuckaby/webcamjs/": "1.0.0",
|
"https://github.com/jhuckaby/webcamjs/": "1.0.0",
|
||||||
"https://github.com/alpinejs/alpine": "3.14.1",
|
"https://github.com/alpinejs/alpine": "3.14.1",
|
||||||
|
"https://github.com/cytoscape/cytoscape.js": "3.30.2 ",
|
||||||
|
"https://github.com/cytoscape/cytoscape.js-cxtmenu": "3.5.0",
|
||||||
|
"https://github.com/cytoscape/cytoscape.js-klay": "3.1.4",
|
||||||
|
"https://github.com/kieler/klayjs": "0.4.1", # Deprecated, elk should be used but cytoscape-elk is broken
|
||||||
"https://github.com/mrdoob/three.js/": "r148",
|
"https://github.com/mrdoob/three.js/": "r148",
|
||||||
"https://github.com/vasturiano/three-spritetext": "1.6.5",
|
"https://github.com/vasturiano/three-spritetext": "1.6.5",
|
||||||
"https://github.com/vasturiano/3d-force-graph/": "1.70.19",
|
"https://github.com/vasturiano/3d-force-graph/": "1.70.19",
|
||||||
|
Loading…
Reference in New Issue
Block a user