Merge pull request 'Some improvements & bugfixes' (#18) from dev into master
All checks were successful
Build on push / prepare (push) Successful in 7s
Build on push / build-redirector (push) Successful in 31s
Build on push / build-api (push) Successful in 32s
Build on push / build-web (push) Successful in 58s

Reviewed-on: #18
This commit is contained in:
Sven Heidemann 2025-03-14 21:08:49 +01:00
commit 0b9489f110
11 changed files with 92 additions and 61 deletions

View File

@ -13,10 +13,11 @@ class DbModelFilterABC[T](FilterABC[T]):
obj: Optional[dict],
):
FilterABC.__init__(self, obj)
from api_graphql.filter.user_filter import UserFilter
self.add_field("id", IntFilter)
self.add_field("deleted", BoolFilter)
self.add_field("editor", IntFilter)
self.add_field("editor", UserFilter)
self.add_field("createdUtc", StringFilter, "created")
self.add_field("updatedUtc", StringFilter, "updated")

View File

@ -1,5 +1,7 @@
from api_graphql.abc.db_model_filter_abc import DbModelFilterABC
from api_graphql.abc.filter.string_filter import StringFilter
from api_graphql.filter.domain_filter import DomainFilter
from api_graphql.filter.group_filter import GroupFilter
class ShortUrlFilter(DbModelFilterABC):
@ -12,3 +14,6 @@ class ShortUrlFilter(DbModelFilterABC):
self.add_field("shortUrl", StringFilter, db_name="short_url")
self.add_field("targetUrl", StringFilter, db_name="target_url")
self.add_field("description", StringFilter)
self.add_field("group", GroupFilter)
self.add_field("domain", DomainFilter)

View File

@ -50,6 +50,8 @@ input ShortUrlFilter {
targetUrl: StringFilter
description: StringFilter
loadingScreen: BooleanFilter
group: GroupFilter
domain: DomainFilter
fuzzy: ShortUrlFuzzy

View File

@ -115,5 +115,5 @@ class ShortUrlMutation(MutationABC):
@staticmethod
async def resolve_track_visit(*_, id: int, agent: str):
logger.debug(f"track visit: {id} -- {agent}")
await shortUrlVisitDao.create(ShortUrlVisit(0, id, agent))
x = await shortUrlVisitDao.create(ShortUrlVisit(0, id, agent))
return True

View File

@ -132,11 +132,15 @@ class DataAccessObjectABC(ABC, Database, Generic[T_DBM]):
async def count(self, filters: AttributeFilters = None) -> int:
query = f"SELECT COUNT(*) FROM {self._table_name}"
for join in self.__joins:
query += f" {self.__joins[join]}"
if filters is not None and (not isinstance(filters, list) or len(filters) > 0):
query += f" WHERE {self._build_conditions(filters)}"
result = await self._db.select_map(query)
if len(result) == 0:
return 0
return result[0]["count"]
async def get_all(self) -> list[T_DBM]:
@ -583,14 +587,16 @@ class DataAccessObjectABC(ABC, Database, Generic[T_DBM]):
if isinstance(sub_values, dict):
for operator, value in sub_values.items():
conditions.append(self._build_condition(db_name, operator, value))
conditions.append(
f"({self._build_condition(db_name, operator, value)} OR {self._build_condition(db_name, "isNull", None)})")
elif isinstance(sub_values, list):
sub_conditions = []
for value in sub_values:
if isinstance(value, dict):
for operator, val in value.items():
sub_conditions.append(
self._build_condition(db_name, operator, val)
f"({self._build_condition(db_name, operator, val)} OR {self._build_condition(db_name, "isNull", None)})"
)
else:
sub_conditions.append(

View File

@ -13,7 +13,9 @@ class ShortUrlDao(DbModelDaoABC[ShortUrl]):
self.attribute(ShortUrl.target_url, str)
self.attribute(ShortUrl.description, str)
self.attribute(ShortUrl.group_id, int)
self.reference("group", "id", ShortUrl.group_id, "public.groups")
self.attribute(ShortUrl.domain_id, int)
self.reference("domain", "id", ShortUrl.domain_id, "public.domains")
self.attribute(ShortUrl.loading_screen, bool)

View File

@ -83,7 +83,7 @@ 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 }} }}) {{
shortUrls(filter: {{ shortUrl: {{ equal: $path }}, deleted: {{ equal: false }}, group: {{ deleted: {{ equal: false }} }} }}) {{
nodes {{
id
shortUrl
@ -107,7 +107,14 @@ def _find_short_url_by_path(path: str) -> Optional[dict]:
},
headers={"Authorization": f"API-Key {api_key}"},
)
data = request.json()["data"]["shortUrls"]["nodes"]
data = request.json()
if "errors" in data:
logger.warning(f"Failed to find short url by path {path} -> {data["errors"]}")
if "data" not in data or "shortUrls" not in data["data"] or "nodes" not in data["data"]["shortUrls"]:
return None
data = data["data"]["shortUrls"]["nodes"]
if len(data) == 0:
return None

View File

@ -115,6 +115,7 @@ export abstract class PageBase<
.onChange()
.pipe(takeUntil(this.unsubscribe$))
.subscribe(() => {
logger.debug('Reload data');
this.load(true);
});
}

View File

@ -41,12 +41,10 @@ export class ShortUrlFormPageComponent extends FormPageBase<
return;
}
this.dataService
.load([{ id: { equal: this.nodeId } }])
.subscribe(apiKey => {
this.node = apiKey.nodes[0];
this.setForm(this.node);
});
this.dataService.loadById(this.nodeId).subscribe(node => {
this.node = node;
this.setForm(this.node);
});
}
new(): ShortUrl {

View File

@ -1,5 +1,5 @@
import { Injectable, Provider } from '@angular/core';
import { Observable } from 'rxjs';
import { merge, Observable } from 'rxjs';
import {
Create,
Delete,
@ -47,13 +47,8 @@ export class ShortUrlsDataService
return this.apollo
.query<{ shortUrls: QueryResult<ShortUrl> }>({
query: gql`
query getShortUrls(
$filter: [ShortUrlFilter]
$sort: [ShortUrlSort]
$skip: Int
$take: Int
) {
shortUrls(filter: $filter, sort: $sort, skip: $skip, take: $take) {
query getShortUrls($filter: [ShortUrlFilter], $sort: [ShortUrlSort]) {
shortUrls(filter: $filter, sort: $sort) {
count
totalCount
nodes {
@ -80,7 +75,7 @@ export class ShortUrlsDataService
${DB_MODEL_FRAGMENT}
`,
variables: {
filter: filter,
filter: [{ group: { deleted: { equal: false } } }, ...(filter ?? [])],
sort: sort,
skip: skip,
take: take,
@ -100,23 +95,25 @@ export class ShortUrlsDataService
.query<{ shortUrls: QueryResult<ShortUrl> }>({
query: gql`
query getShortUrl($id: Int) {
shortUrl(filter: { id: { equal: $id } }) {
id
shortUrl
targetUrl
description
loadingScreen
visits
group {
shortUrls(filter: { id: { equal: $id } }) {
nodes {
id
name
}
domain {
id
name
}
shortUrl
targetUrl
description
loadingScreen
visits
group {
id
name
}
domain {
id
name
}
...DB_MODEL
...DB_MODEL
}
}
}
@ -136,15 +133,27 @@ export class ShortUrlsDataService
}
onChange(): Observable<void> {
return this.apollo
.subscribe<{ shortUrlChange: void }>({
query: gql`
subscription onShortUrlChange {
shortUrlChange
}
`,
})
.pipe(map(result => result.data?.shortUrlChange));
return merge(
this.apollo
.subscribe<{ shortUrlChange: void }>({
query: gql`
subscription onShortUrlChange {
shortUrlChange
}
`,
})
.pipe(map(result => result.data?.shortUrlChange)),
this.apollo
.subscribe<{ groupChange: void }>({
query: gql`
subscription onGroupChange {
groupChange
}
`,
})
.pipe(map(result => result.data?.groupChange))
).pipe(map(() => {}));
}
create(object: ShortUrlCreateInput): Observable<ShortUrl | undefined> {

View File

@ -1,34 +1,34 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { SharedModule } from "src/app/modules/shared/shared.module";
import { RouterModule, Routes } from "@angular/router";
import { PermissionGuard } from "src/app/core/guard/permission.guard";
import { PermissionsEnum } from "src/app/model/auth/permissionsEnum";
import { ShortUrlsPage } from "src/app/modules/admin/short-urls/short-urls.page";
import { ShortUrlFormPageComponent } from "src/app/modules/admin/short-urls/form-page/short-url-form-page.component";
import { ShortUrlsDataService } from "src/app/modules/admin/short-urls/short-urls.data.service";
import { ShortUrlsColumns } from "src/app/modules/admin/short-urls/short-urls.columns";
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from 'src/app/modules/shared/shared.module';
import { RouterModule, Routes } from '@angular/router';
import { PermissionGuard } from 'src/app/core/guard/permission.guard';
import { PermissionsEnum } from 'src/app/model/auth/permissionsEnum';
import { ShortUrlsPage } from 'src/app/modules/admin/short-urls/short-urls.page';
import { ShortUrlFormPageComponent } from 'src/app/modules/admin/short-urls/form-page/short-url-form-page.component';
import { ShortUrlsDataService } from 'src/app/modules/admin/short-urls/short-urls.data.service';
import { ShortUrlsColumns } from 'src/app/modules/admin/short-urls/short-urls.columns';
const routes: Routes = [
{
path: "",
title: "ShortUrls",
path: '',
title: 'ShortUrls',
component: ShortUrlsPage,
children: [
{
path: "create",
path: 'create',
component: ShortUrlFormPageComponent,
canActivate: [PermissionGuard],
data: {
permissions: [PermissionsEnum.apiKeysCreate],
permissions: [PermissionsEnum.shortUrlsCreate],
},
},
{
path: "edit/:id",
path: 'edit/:id',
component: ShortUrlFormPageComponent,
canActivate: [PermissionGuard],
data: {
permissions: [PermissionsEnum.apiKeysUpdate],
permissions: [PermissionsEnum.shortUrlsUpdate],
},
},
],