Fixed redirector #15
Some checks failed
Test API before pr merge / test-lint (pull_request) Successful in 11s
Test before pr merge / test-translation-lint (pull_request) Successful in 42s
Test before pr merge / test-lint (pull_request) Failing after 44s
Test before pr merge / test-before-merge (pull_request) Successful in 1m44s

This commit is contained in:
Sven Heidemann 2025-05-02 11:29:54 +02:00
parent 16bc5d570b
commit a913ea014f
5 changed files with 132 additions and 101 deletions

View File

@ -11,3 +11,4 @@ Jinja2==3.1.5
python-keycloak==5.3.1
python-multipart==0.0.20
websockets==15.0
sqlparse==0.5.3

View File

@ -1,5 +1,6 @@
from typing import Optional, Any
import sqlparse
from psycopg import sql
from psycopg_pool import AsyncConnectionPool, PoolTimeout
@ -44,7 +45,9 @@ class PostgresPool:
@staticmethod
async def _exec_sql(cursor: Any, query: str, args=None, multi=True):
if multi:
queries = query.split(";")
queries = [
str(stmt).strip() for stmt in sqlparse.parse(query) if str(stmt).strip()
]
for q in queries:
if q.strip() == "":
continue

View File

@ -15,7 +15,9 @@ class ShortUrlVisitDao(DbModelDaoABC[ShortUrlVisit]):
async def count_by_id(self, fid: int) -> int:
result = await self._db.select_map(
f"SELECT COUNT(*) FROM {self._table_name} WHERE shortUrlId = {fid}"
f"""SELECT COUNT(*) FROM {self._table_name}
WHERE shortUrlId = {fid}
AND deleted = FALSE"""
)
if result is None or len(result) == 0:
return 0

View File

@ -83,7 +83,26 @@ def _find_short_url_by_path(path: str) -> Optional[dict]:
json={
"query": f"""
query getShortUrlByPath($path: String!) {{
shortUrls(filter: {{ shortUrl: {{ equal: $path }}, deleted: {{ equal: false }}, group: {{ deleted: {{ equal: false }} }} }}) {{
shortUrls(filter: [{{ shortUrl: {{ equal: $path }} }}, {{ deleted: {{ equal: false }} }}, {{ group: {{ deleted: {{ equal: false }} }} }}]) {{
nodes {{
id
shortUrl
targetUrl
description
group {{
id
name
}}
domain {{
id
name
}}
loadingScreen
deleted
}}
}}
shortUrlsWithoutGroup: shortUrls(filter: [{{ shortUrl: {{ equal: $path }} }}, {{ deleted: {{ equal: false }} }}, {{ group: {{ isNull: true }} }}]) {{
nodes {{
id
shortUrl
@ -115,14 +134,18 @@ def _find_short_url_by_path(path: str) -> Optional[dict]:
"data" not in data
or "shortUrls" not in data["data"]
or "nodes" not in data["data"]["shortUrls"]
or "nodes" not in data["data"]["shortUrlsWithoutGroup"]
):
return None
data = data["data"]["shortUrls"]["nodes"]
if len(data) == 0:
nodes = [
*data["data"]["shortUrls"]["nodes"],
*data["data"]["shortUrlsWithoutGroup"]["nodes"],
]
if len(nodes) == 0:
return None
return data[0]
return nodes[0]
async def _handle_short_url(request: Request, short_url: dict):
@ -145,7 +168,7 @@ async def _track_visit(r: Request, short_url: dict):
f"{api_url}/graphql",
json={
"query": f"""
mutation trackShortUrlVisit($id: ID!, $agent: String) {{
mutation trackShortUrlVisit($id: Int!, $agent: String) {{
shortUrl {{
trackVisit(id: $id, agent: $agent)
}}

View File

@ -50,111 +50,113 @@ export class ShortUrlsDataService
skip?: number | undefined,
take?: number | undefined
): Observable<QueryResult<ShortUrl>> {
const query1 = this.apollo.query<{ shortUrls: QueryResult<ShortUrl> }>({
query: gql`
query getShortUrls($filter: [ShortUrlFilter], $sort: [ShortUrlSort]) {
shortUrls(filter: $filter, sort: $sort) {
nodes {
id
shortUrl
targetUrl
description
loadingScreen
visits
group {
return this.apollo
.query<{
shortUrls: QueryResult<ShortUrl>;
shortUrlsWithoutGroup: QueryResult<ShortUrl>;
}>({
query: gql`
query getShortUrls(
$filter: [ShortUrlFilter]
$filter2: [ShortUrlFilter]
$sort: [ShortUrlSort]
) {
shortUrls(filter: $filter, sort: $sort) {
nodes {
id
name
}
domain {
id
name
}
shortUrl
targetUrl
description
loadingScreen
visits
group {
id
name
}
domain {
id
name
}
...DB_MODEL
...DB_MODEL
}
}
shortUrlsWithoutGroup: shortUrls(filter: $filter2, sort: $sort) {
nodes {
id
shortUrl
targetUrl
description
loadingScreen
visits
group {
id
name
}
domain {
id
name
}
...DB_MODEL
}
}
}
}
${DB_MODEL_FRAGMENT}
`,
variables: {
filter: [
{
userSpace: {
id: { equal: this.sidebarService.selectedUserSpace$.value?.id },
},
},
{ group: { deleted: { equal: false } } },
{
group: {
${DB_MODEL_FRAGMENT}
`,
variables: {
filter: [
{
userSpace: {
id: { equal: this.sidebarService.selectedUserSpace$.value?.id },
},
},
},
...(filter ?? []),
],
sort: [{ id: SortOrder.DESC }, ...(sort ?? [])],
skip,
take,
},
});
const query2 = this.apollo.query<{ shortUrls: QueryResult<ShortUrl> }>({
query: gql`
query getShortUrls($filter: [ShortUrlFilter], $sort: [ShortUrlSort]) {
shortUrls(filter: $filter, sort: $sort) {
nodes {
id
shortUrl
targetUrl
description
loadingScreen
visits
group {
id
name
}
domain {
id
name
}
...DB_MODEL
}
}
}
${DB_MODEL_FRAGMENT}
`,
variables: {
filter: [
{
userSpace: {
id: { equal: this.sidebarService.selectedUserSpace$.value?.id },
{ group: { deleted: { equal: false } } },
{
group: {
userSpace: {
id: {
equal: this.sidebarService.selectedUserSpace$.value?.id,
},
},
},
},
},
{ group: { isNull: true } },
...(filter ?? []),
],
sort: [{ id: SortOrder.DESC }, ...(sort ?? [])],
skip,
take,
},
});
return forkJoin([query1, query2]).pipe(
map(([result1, result2]) => {
const nodes = [
...result1.data.shortUrls.nodes,
...result2.data.shortUrls.nodes,
];
const uniqueNodes = Array.from(
new Map(nodes.map(node => [node.id, node])).values()
);
return { ...result1.data.shortUrls, nodes: uniqueNodes };
...(filter ?? []),
],
filter2: [
{
userSpace: {
id: { equal: this.sidebarService.selectedUserSpace$.value?.id },
},
},
{
group: {
isNull: true,
},
},
...(filter ?? []),
],
sort: [{ id: SortOrder.DESC }, ...(sort ?? [])],
skip,
take,
},
})
);
.pipe(
map(x => {
return {
count: x.data.shortUrls.count + x.data.shortUrlsWithoutGroup.count,
totalCount:
x.data.shortUrls.totalCount +
x.data.shortUrlsWithoutGroup.totalCount,
nodes: [
...x.data.shortUrls.nodes,
...x.data.shortUrlsWithoutGroup.nodes,
],
};
})
);
}
loadById(id: number): Observable<ShortUrl> {