Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe95525386 | |||
| 1af8a4be9a | |||
| 92473a2f52 | |||
| dc5f8ddb51 | |||
| d90504eed9 | |||
| 9565a71bc8 | |||
| dbb01a5225 | |||
| 0611ceb3ec | |||
| 3c71464663 | |||
| c842657766 | |||
| e2b2455bea | |||
| 1b775a130b | |||
| bcef0d2d09 | |||
| 9f121a0ceb | |||
| d16f0cd957 | |||
| 98e5e1891a | |||
| 06343e6ed3 | |||
| 82a3b612ec | |||
| 1e549d3fc2 | |||
| 55126f4af6 | |||
| cca49f2292 | |||
| 23f8296659 | |||
| 9abed01e53 | |||
| 3b1aba9672 | |||
| 22061486a8 | |||
| 38785ccf92 | |||
| 1f78a4a079 | |||
| 20fa33abeb |
@@ -75,6 +75,8 @@ jobs:
|
||||
--push \
|
||||
--platform "${{ inputs.platform }}" \
|
||||
--build-arg IMAGE_ID="${{ inputs.target }}.${SHORT_SHA}" \
|
||||
--build-arg IMAGE_VERSION="${VERSION}" \
|
||||
--build-arg IMAGE_REVISION="${SHORT_SHA}" \
|
||||
-f services/backend/Dockerfile \
|
||||
--target "${{ inputs.target }}" \
|
||||
-t "${{ inputs.registry }}/hotpocket/backend:${{ inputs.target }}-${VERSION}-${BUILD}" \
|
||||
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
set -x
|
||||
|
||||
(
|
||||
cd deployment/hotpocket.bthlab ;
|
||||
cd deployment/hotpocket_bthlab ;
|
||||
export KUBECONFIG="/opt/k8s/etc/kubeconfig" ;
|
||||
/opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ;
|
||||
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} apply -f resources/backend/config-map-local-deps.yaml ;
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
run: |
|
||||
set -x
|
||||
(
|
||||
cd deployment/hotpocket.bthlab ;
|
||||
cd deployment/hotpocket_bthlab ;
|
||||
export KUBECONFIG="/opt/k8s/etc/kubeconfig" ;
|
||||
/opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ;
|
||||
/opt/k8s/bin/kustomize edit set image hotpocket-backend=nexus.bthlab.bthlabs.net:8002/hotpocket/backend:${BACKEND_TAG} ;
|
||||
|
||||
35
README.md
@@ -1,13 +1,30 @@
|
||||
# HotPocket by BTHLabs
|
||||
|
||||
This repository contains the _HotPocket_ project.
|
||||
Minimal self-hosted bookmarking app :).
|
||||
|
||||
## The what, the why and the ugly
|
||||
|
||||
HotPocket is a minimal self-hosted bookmarking app. It combines a Web
|
||||
application, companion apps, browser extensions to give you a way to quickly
|
||||
save links for later.
|
||||
|
||||
HotPocket came to be to fill in the blank left by Pocket, after Mozilla shut it
|
||||
down. I looked at the existing alternatives and found them either too
|
||||
feature-rich, too involved to self-host or otherwise not to my liking. So I
|
||||
decided to sit down and build something for myself.
|
||||
|
||||
With the what and why out of the way, let's talk about the ugly... At its core
|
||||
HotPocket is a personal project. I built it by myself and for myself. It may
|
||||
or may not fit your needs. If it does, happy saving!
|
||||
|
||||
If you're feeling up for an adventure, continue reading below :).
|
||||
|
||||
## Development setup
|
||||
|
||||
### Requirements:
|
||||
|
||||
* Python 3.12,
|
||||
* Poetry 1.8.3,
|
||||
* Python 3.13,
|
||||
* Poetry 2.2.1,
|
||||
* `git-crypt`,
|
||||
* Docker with Docker Compose and Buildx.
|
||||
|
||||
@@ -66,7 +83,7 @@ $ docker run --rm -it \
|
||||
-e HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME=hotpocket \
|
||||
-e HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD=hotpocketm4st3r \
|
||||
-p 8000:8000 \
|
||||
docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-v25.11.12-01
|
||||
hotpocket/backend:aio-v26.8.22-01
|
||||
```
|
||||
|
||||
The command above will set up and start the application. The SQLite file will
|
||||
@@ -128,6 +145,7 @@ that can be used to configure the services.
|
||||
| `HOTPOCKET_BACKEND_RUN_MIGRATIONS` | `false` or `true` | Set to `true` to run database muigrations when the container starts. |
|
||||
| `HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME` | N/A | Username for the initial account. |
|
||||
| `HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD` | N/A | Password for the initial account. |
|
||||
| `HOTPOCKET_BACKEND_OPERATOR_EMAIL` | N/A | Instance operator's e-mail. Used to display extra language on login page. |
|
||||
|
||||
**Env and App settings**
|
||||
|
||||
@@ -158,6 +176,15 @@ method's name in the UI and defaults to `OIDC`.
|
||||
|
||||
**NOTE:** Currently, only Keycloak has been tested with this login method.
|
||||
|
||||
### Volumes
|
||||
|
||||
Both images declare `/srv/run` to be a volume. It's intended to keep the
|
||||
service's runtime data, including but not limited to PID files, UNIX sockets
|
||||
etc. It's recommended to persist this volume.
|
||||
|
||||
Additionally, the `deployment` image declares `/srv/uploads` to be a volume.
|
||||
It's recommeded to persist this volume.
|
||||
|
||||
## Author
|
||||
|
||||
_HotPocket_ is developed by [BTHLabs](https://www.bthlabs.pl/).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
backend:
|
||||
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-v25.11.12-01"
|
||||
image: "bthlabs/hotpocket:aio-v26.8.22-01"
|
||||
environment:
|
||||
HOTPOCKET_BACKEND_SECRET_KEY: "thisisntright"
|
||||
HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME: "hotpocket"
|
||||
|
||||
@@ -8,7 +8,7 @@ x-backend-environment: &x-backend-environment
|
||||
|
||||
services:
|
||||
webapp:
|
||||
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.12-01"
|
||||
image: "bthlabs/hotpocket:deployment-v26.8.22-01"
|
||||
environment:
|
||||
<<: *x-backend-environment
|
||||
HOTPOCKET_BACKEND_ALLOWED_HOSTS: "app.staging.hotpocket.bthlab.bthlabs.net"
|
||||
@@ -21,7 +21,7 @@ services:
|
||||
restart: "unless-stopped"
|
||||
|
||||
admin:
|
||||
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.12-01"
|
||||
image: "bthlabs/hotpocket:deployment-v26.8.22-01"
|
||||
environment:
|
||||
<<: *x-backend-environment
|
||||
HOTPOCKET_BACKEND_APP: "admin"
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
restart: "unless-stopped"
|
||||
|
||||
celery-worker:
|
||||
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.12-01"
|
||||
image: "bthlabs/hotpocket:deployment-v26.8.22-01"
|
||||
command:
|
||||
- "/srv/venv/bin/celery"
|
||||
- "-A"
|
||||
@@ -57,7 +57,7 @@ services:
|
||||
restart: "unless-stopped"
|
||||
|
||||
celery-beat:
|
||||
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.12-01"
|
||||
image: "bthlabs/hotpocket:deployment-v26.8.22-01"
|
||||
command:
|
||||
- "/srv/venv/bin/celery"
|
||||
- "-A"
|
||||
|
||||
@@ -8,7 +8,7 @@ hotpocket_app:
|
||||
node: "home.vm.snakeweb.net"
|
||||
docker:
|
||||
extra_hosts:
|
||||
- "home.vm:10.0.1.2"
|
||||
- "home.vm:10.16.1.100"
|
||||
backend:
|
||||
image_tag: "{{ hotpocket_app_image_tag|default('deployment-v25.10.21-01') }}"
|
||||
database:
|
||||
|
||||
6
poetry.lock
generated
@@ -5,7 +5,7 @@ name = "hotpocket-workspace-tools"
|
||||
version = "1.0.0.dev0"
|
||||
description = "HotPocket Workspace Tools"
|
||||
optional = false
|
||||
python-versions = "^3.12"
|
||||
python-versions = "^3.13"
|
||||
groups = ["main"]
|
||||
files = []
|
||||
develop = true
|
||||
@@ -31,5 +31,5 @@ files = [
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "a7028d4a0260c82012077d9cc4b324b0ef5ab8ed24aa283a51cf941ba09685a9"
|
||||
python-versions = "^3.13"
|
||||
content-hash = "175bf795c7148fe40af7e095d6f41918fa14cf4c71be87444a4d6c467fbd38d2"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[tool.poetry]
|
||||
name = "hotpocket-workspace"
|
||||
version = "25.11.12"
|
||||
version = "26.8.22"
|
||||
description = "HotPocket Workspace"
|
||||
authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
|
||||
license = "Apache-2.0"
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
python = "^3.13"
|
||||
hotpocket-workspace-tools = {path = "services/packages/workspace_tools", develop = true}
|
||||
|
||||
[build-system]
|
||||
|
||||
2
services/apple/.gitignore
vendored
@@ -92,3 +92,5 @@ Shared (Extension)/Resources/content-bundle.js
|
||||
Shared (Extension)/Resources/manifest.json
|
||||
Shared (Extension)/Resources/preauth.html
|
||||
Shared (Extension)/Resources/preauth.js
|
||||
Shared (Extension)/Resources/options.html
|
||||
Shared (Extension)/Resources/options.js
|
||||
|
||||
@@ -2,7 +2,7 @@ ARG APP_USER_UID=1000
|
||||
ARG APP_USER_GID=1000
|
||||
ARG IMAGE_ID=development.00000000
|
||||
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:build-node-20251014-01 AS development
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:build-node-20260818-01 AS development
|
||||
|
||||
ARG APP_USER_UID
|
||||
ARG APP_USER_GID
|
||||
|
||||
@@ -85,8 +85,8 @@
|
||||
4C70F3142E886A8F00320048 /* HPSharedItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HPSharedItem.m; sourceTree = "<group>"; };
|
||||
4C70F3172E886ADD00320048 /* HPSharedItemsContainer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HPSharedItemsContainer.h; sourceTree = "<group>"; };
|
||||
4C70F3182E886ADD00320048 /* HPSharedItemsContainer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HPSharedItemsContainer.m; sourceTree = "<group>"; };
|
||||
4CABCAB02E56F0C900D8A354 /* HotPocket.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HotPocket.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4CABCAC62E56F0C900D8A354 /* HotPocket.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HotPocket.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4CABCAB02E56F0C900D8A354 /* HotPocket Development.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "HotPocket Development.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4CABCAC62E56F0C900D8A354 /* HotPocket Development.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "HotPocket Development.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4CABCAD52E56F0C900D8A354 /* HotPocket Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "HotPocket Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4CABCADF2E56F0C900D8A354 /* HotPocket Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "HotPocket Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4CBCEA4F2E81CB9500722009 /* Save to HotPocket.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Save to HotPocket.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -104,10 +104,13 @@
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Assets.xcassets,
|
||||
"HotPocket 27.icon",
|
||||
HPAPI.m,
|
||||
HPCredentialsHelper.m,
|
||||
HPRPCClient.m,
|
||||
"NSBundle+HotPocketExtensions.m",
|
||||
"NSURL+HotPocketExtensions.m",
|
||||
"Resources/icon-glass-512.png",
|
||||
"Resources/icon-mac-384.png",
|
||||
);
|
||||
target = 4C2F0C5D2E851BBD0033F5C2 /* iOS (Share Extension) */;
|
||||
@@ -123,6 +126,7 @@
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
MultilineLabel.m,
|
||||
UnameLabel.m,
|
||||
);
|
||||
target = 4C2F0C5D2E851BBD0033F5C2 /* iOS (Share Extension) */;
|
||||
};
|
||||
@@ -130,11 +134,14 @@
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Assets.xcassets,
|
||||
"HotPocket 27.icon",
|
||||
HPAPI.m,
|
||||
HPAuthFlow.m,
|
||||
HPCredentialsHelper.m,
|
||||
HPRPCClient.m,
|
||||
"NSBundle+HotPocketExtensions.m",
|
||||
"NSURL+HotPocketExtensions.m",
|
||||
"Resources/icon-glass-512.png",
|
||||
"Resources/icon-mac-384.png",
|
||||
);
|
||||
target = 4CABCAAF2E56F0C900D8A354 /* HotPocket (iOS) */;
|
||||
@@ -157,11 +164,14 @@
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Assets.xcassets,
|
||||
"HotPocket 27.icon",
|
||||
HPAPI.m,
|
||||
HPAuthFlow.m,
|
||||
HPCredentialsHelper.m,
|
||||
HPRPCClient.m,
|
||||
"NSBundle+HotPocketExtensions.m",
|
||||
"NSURL+HotPocketExtensions.m",
|
||||
"Resources/icon-glass-512.png",
|
||||
"Resources/icon-mac-384.png",
|
||||
);
|
||||
target = 4CABCAC52E56F0C900D8A354 /* HotPocket (macOS) */;
|
||||
@@ -181,6 +191,8 @@
|
||||
"Resources/content-bundle.js",
|
||||
Resources/images,
|
||||
Resources/manifest.json,
|
||||
Resources/options.html,
|
||||
Resources/options.js,
|
||||
Resources/preauth.html,
|
||||
Resources/preauth.js,
|
||||
SafariWebExtensionHandler.m,
|
||||
@@ -195,6 +207,8 @@
|
||||
"Resources/content-bundle.js",
|
||||
Resources/images,
|
||||
Resources/manifest.json,
|
||||
Resources/options.html,
|
||||
Resources/options.js,
|
||||
Resources/preauth.html,
|
||||
Resources/preauth.js,
|
||||
SafariWebExtensionHandler.m,
|
||||
@@ -212,10 +226,13 @@
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Assets.xcassets,
|
||||
"HotPocket 27.icon",
|
||||
HPAPI.m,
|
||||
HPCredentialsHelper.m,
|
||||
HPRPCClient.m,
|
||||
"NSBundle+HotPocketExtensions.m",
|
||||
"NSURL+HotPocketExtensions.m",
|
||||
"Resources/icon-glass-512.png",
|
||||
"Resources/icon-mac-384.png",
|
||||
);
|
||||
target = 4CBCEA4E2E81CB9500722009 /* macOS (Share Extension) */;
|
||||
@@ -384,8 +401,8 @@
|
||||
4CABCAB12E56F0C900D8A354 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CABCAB02E56F0C900D8A354 /* HotPocket.app */,
|
||||
4CABCAC62E56F0C900D8A354 /* HotPocket.app */,
|
||||
4CABCAB02E56F0C900D8A354 /* HotPocket Development.app */,
|
||||
4CABCAC62E56F0C900D8A354 /* HotPocket Development.app */,
|
||||
4CABCAD52E56F0C900D8A354 /* HotPocket Extension.appex */,
|
||||
4CABCADF2E56F0C900D8A354 /* HotPocket Extension.appex */,
|
||||
4CBCEA4F2E81CB9500722009 /* Save to HotPocket.appex */,
|
||||
@@ -441,7 +458,7 @@
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = "HotPocket (iOS)";
|
||||
productReference = 4CABCAB02E56F0C900D8A354 /* HotPocket.app */;
|
||||
productReference = 4CABCAB02E56F0C900D8A354 /* HotPocket Development.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
4CABCAC52E56F0C900D8A354 /* HotPocket (macOS) */ = {
|
||||
@@ -466,7 +483,7 @@
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = "HotPocket (macOS)";
|
||||
productReference = 4CABCAC62E56F0C900D8A354 /* HotPocket.app */;
|
||||
productReference = 4CABCAC62E56F0C900D8A354 /* HotPocket Development.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
4CABCAD42E56F0C900D8A354 /* HotPocket Extension (iOS) */ = {
|
||||
@@ -713,7 +730,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "iOS (Share Extension)/iOS (Share Extension).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "iOS (Share Extension)/Info.plist";
|
||||
@@ -726,7 +743,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
|
||||
PRODUCT_NAME = "Save to HotPocket";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -746,7 +763,7 @@
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = "iOS (Share Extension)/iOS (Share Extension).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "iOS (Share Extension)/Info.plist";
|
||||
@@ -759,7 +776,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
|
||||
PRODUCT_NAME = "Save to HotPocket";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -778,8 +795,9 @@
|
||||
4CABCB062E56F0C900D8A354 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "HotPocket 27";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "iOS (Extension)/Info.plist";
|
||||
@@ -792,7 +810,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -813,8 +831,9 @@
|
||||
4CABCB072E56F0C900D8A354 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "HotPocket 27";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "iOS (Extension)/Info.plist";
|
||||
@@ -827,7 +846,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -849,11 +868,11 @@
|
||||
4CABCB0B2E56F0C900D8A354 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "HotPocket 27";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "iOS (App)/HotPocket (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "iOS (App)/Info.plist";
|
||||
@@ -873,7 +892,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -881,7 +900,7 @@
|
||||
WebKit,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket;
|
||||
PRODUCT_NAME = HotPocket;
|
||||
PRODUCT_NAME = "HotPocket Development";
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
@@ -895,11 +914,11 @@
|
||||
4CABCB0C2E56F0C900D8A354 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "HotPocket 27";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "iOS (App)/HotPocket (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "iOS (App)/Info.plist";
|
||||
@@ -919,7 +938,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -945,7 +964,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/HotPocket.entitlements";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -960,7 +979,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -980,7 +999,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/HotPocket.entitlements";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -995,7 +1014,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -1012,12 +1031,12 @@
|
||||
4CABCB152E56F0C900D8A354 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "HotPocket 27";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS (App)/HotPocket.entitlements";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1033,7 +1052,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -1041,7 +1060,7 @@
|
||||
WebKit,
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket;
|
||||
PRODUCT_NAME = HotPocket;
|
||||
PRODUCT_NAME = "HotPocket Development";
|
||||
REGISTER_APP_GROUPS = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
@@ -1051,12 +1070,12 @@
|
||||
4CABCB162E56F0C900D8A354 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = "HotPocket 27";
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS (App)/HotPocket.entitlements";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1072,7 +1091,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
OTHER_LDFLAGS = (
|
||||
"-framework",
|
||||
SafariServices,
|
||||
@@ -1206,7 +1225,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS (Share Extension)/macOS (Share Extension).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1220,7 +1239,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
|
||||
PRODUCT_NAME = "Save to HotPocket";
|
||||
REGISTER_APP_GROUPS = YES;
|
||||
@@ -1236,7 +1255,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "macOS (Share Extension)/macOS (Share Extension).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2025111201;
|
||||
CURRENT_PROJECT_VERSION = 2026082201;
|
||||
DEVELOPMENT_TEAM = 648728X64K;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -1250,7 +1269,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.0;
|
||||
MARKETING_VERSION = 25.11.12;
|
||||
MARKETING_VERSION = 26.8.22;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
|
||||
PRODUCT_NAME = "Save to HotPocket";
|
||||
REGISTER_APP_GROUPS = YES;
|
||||
|
||||
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 264 KiB |
@@ -10,6 +10,7 @@
|
||||
#import "HPAPI.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "HPRPCClient.h"
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
#import "NSURL+HotPocketExtensions.h"
|
||||
|
||||
@implementation HPAuthParams
|
||||
@@ -77,18 +78,19 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary *postAuthenticateURLParams = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"HPAuthFlowPostAuthenticateURLParts"];
|
||||
if (postAuthenticateURLParams == nil) {
|
||||
NSString *expectedScheme = [NSBundle postAuthenticateURLScheme];
|
||||
NSString *expectedHost = [NSBundle postAuthenticateURLHost];
|
||||
if (expectedScheme == nil || expectedHost == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
|
||||
|
||||
if ([urlComponents.scheme isEqualToString:[postAuthenticateURLParams valueForKey:@"scheme"]] == NO) {
|
||||
if ([urlComponents.scheme isEqualToString:expectedScheme] == NO) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([urlComponents.host isEqualToString:[postAuthenticateURLParams valueForKey:@"host"]] == NO) {
|
||||
if ([urlComponents.host isEqualToString:expectedHost] == NO) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -109,6 +111,8 @@
|
||||
}
|
||||
|
||||
-(BOOL)handleAuthParams:(HPAuthParams *)authParams {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"AuthFlowDidReceiveAuthParams" object:self];
|
||||
|
||||
HPRPCClient *rpcClient = [[HPRPCClient alloc] initWithBaseURL:self.baseURL accessToken:nil];
|
||||
|
||||
NSArray *callParams = @[
|
||||
@@ -120,7 +124,7 @@
|
||||
method:@"accounts.access_tokens.create"
|
||||
params:callParams endopoint:@"/accounts/rpc/"
|
||||
completionHandler:^(NSString *callId, HPRPCCallResult *result) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (result.error != nil) {
|
||||
NSLog(@"-[HPAuthFlow handleAuthParams:] error=`%@`", result.error);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
|
||||
<title>icon-ios-tinted</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<filter x="-1.5%" y="-1.5%" width="103.0%" height="103.0%" filterUnits="objectBoundingBox" id="filter-1">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="icon-ios-tinted" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="HotPocket-Copy" transform="translate(112.000000, 136.000000)" fill="#1CBAED" fill-rule="nonzero">
|
||||
<g id="Group" filter="url(#filter-1)">
|
||||
<g id="pepper-hot-solid-svgrepo-com" transform="translate(174.000000, 78.000000)">
|
||||
<path d="M452,37.5215494 L452,0 C414.620964,0 385.466785,10.4063766 365.41868,30.779396 C353.815765,42.5781598 347.57369,55.6960499 343.975301,66.9818378 C334.428601,60.3862436 323.339725,56.2823241 311.002439,56.2823241 C263.562643,56.2823241 245.644203,93.9504515 245.203576,119.599939 C245.203576,123.703858 245.056713,128.027635 244.762969,132.497971 C232.131937,169.799663 207.604227,145.102867 207.604227,93.8038736 C147.019342,158.0009 212.304145,181.671725 175.071972,218.826858 C167.140859,226.74156 148.194321,229.81949 136.371093,215.309213 C120.729162,196.768277 152.527064,166.282018 122.4182,143.490622 C127.925922,177.787663 101.415448,170.679075 92.4562182,163.350647 C80.7798529,153.8237 59.5567872,132.864388 94.8061776,75.0430988 C58.748984,91.4587767 37.0118599,124.803127 38.407153,150.086198 C42.1524054,216.408463 144.889696,274.009913 103.398212,312.704011 C82.4688909,332.270918 41.3446022,305.81528 57.2068278,262.650846 C37.4524867,272.690787 14.246638,296.581471 21.6636925,333.736603 C26.804238,359.45937 64.2567059,417.427237 0.807803229,450.258593 C0.807803229,450.258593 1.10154815,450.331873 1.61560646,450.478451 L0,487.780142 C1.24843001,487.853422 6.31552517,488 14.4669514,488 C67.341037,488 250.344122,479.865441 362.995289,372.210844 C422.038018,315.781942 452,241.03198 452,150.086198 C452,124.143573 440.176772,75.0430988 395.600975,75.0430988 C390.093253,75.0430988 384.952727,75.775951 380.105926,76.9484994 C382.235591,70.6460423 385.907393,63.4641926 392.222918,57.0151763 C405.000813,44.1171437 425.048899,37.5215494 452,37.5215494 Z M395.600975,112.564648 C413.372552,112.564648 414.40065,149.793061 414.40065,150.086198 C414.40065,230.332485 388.330784,295.921917 337.072305,345.022372 C253.869061,424.609106 122.785376,444.322571 51.6256743,449.012765 C68.9566246,445.055405 89.8125139,436.994144 112.651186,421.604436 C222.658649,361.43805 280.526398,219.559692 282.656063,125.096264 L282.802926,125.096264 L282.802926,119.966355 C282.876358,115.569299 284.638827,93.8038736 311.002439,93.8038736 C327.084978,93.8038736 339.201951,116.595288 339.201951,131.325423 L376.801301,131.325423 C376.801301,123.264162 378.784083,112.564648 395.600975,112.564648 Z" id="Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="1024px" height="1024px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 61 (89581) - https://sketch.com -->
|
||||
<title>icon-ios-tinted</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<filter x="-1.5%" y="-1.5%" width="103.0%" height="103.0%" filterUnits="objectBoundingBox" id="filter-1">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
|
||||
<feMerge>
|
||||
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="icon-ios-tinted" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="HotPocket-Copy" transform="translate(112.000000, 136.000000)" fill="#0082DD" fill-rule="nonzero">
|
||||
<g id="Group" filter="url(#filter-1)">
|
||||
<g id="patch-fashion-svgrepo-com">
|
||||
<path d="M786.667187,0 L13.3328125,0 C5.3328125,0 0,5.3328125 0,13.3328125 L0,573.332813 C0,578.665625 2.6671875,582.665625 6.6671875,585.332813 L393.334375,798.665625 C396,800 397.332812,800 400,800 C402.667187,800 404,800 406.667187,798.667187 L793.334375,585.334375 C797.334375,582.667188 800.001562,578.667188 800.001562,573.334375 L800.001562,13.3328125 C800.001562,5.3328125 794.667187,0 786.667187,0 Z M773.334375,565.332812 L400,770.667187 L26.6671875,565.332812 L26.6671875,26.6671875 L773.334375,26.6671875 L773.334375,565.332812 L773.334375,565.332812 Z" id="Shape"></path>
|
||||
<path d="M86.6671875,537.332812 L138.667188,566.665625 C141.334375,567.998437 142.667188,567.998437 145.334375,567.998437 C150.667188,567.998437 154.667188,565.33125 157.334375,562.665625 C161.334375,555.998437 158.667187,547.998437 152.001562,543.998437 L106.66875,518.665625 L106.66875,466.665625 C106.66875,458.665625 101.335937,453.332812 93.3359375,453.332812 C85.3359375,453.332812 80.0031223,458.665625 80.0031223,466.665625 L80.0031223,526.665625 C80,530.667187 82.6671875,536 86.6671875,537.332812 Z" id="Path"></path>
|
||||
<path d="M93.3328125,390.667187 C101.332813,390.667187 106.665625,384 106.665625,377.334375 L106.665625,242.667187 C106.665625,234.667187 101.332813,229.334375 93.3328125,229.334375 C85.3328125,229.334375 80,234.667188 80,242.667187 L80,377.334375 C80,385.332812 85.3328125,390.667187 93.3328125,390.667187 Z" id="Path"></path>
|
||||
<path d="M93.3328125,166.667188 C101.332813,166.667188 106.665625,161.334375 106.665625,153.334375 L106.665625,106.667188 L153.332812,106.667188 C161.332813,106.667188 166.665625,101.334375 166.665625,93.334375 C166.665625,85.334375 161.332813,80.0015625 153.332812,80.0015625 L93.3328125,80.0015625 C85.3328125,80.0015625 80,85.334375 80,93.334375 L80,153.334375 C80,161.332813 85.3328125,166.667188 93.3328125,166.667188 Z" id="Path"></path>
|
||||
<path d="M236,106.667188 L358.667188,106.667188 C366.667188,106.667188 372,101.334375 372,93.334375 C372,85.334375 366.667188,80.0015625 358.667188,80.0015625 L236,80.0015625 C228,80.0015625 222.667188,85.334375 222.667188,93.334375 C222.667188,101.334375 228,106.667188 236,106.667188 Z" id="Path"></path>
|
||||
<path d="M441.332812,106.667187 L564,106.667187 C572,106.667187 577.332812,101.334375 577.332812,93.334375 C577.332812,85.334375 572,80 564,80 L441.332812,80 C433.332812,80 428,85.3328125 428,93.3328125 C428,101.332813 433.332812,106.667187 441.332812,106.667187 Z" id="Path"></path>
|
||||
<path d="M646.667188,106.667187 L693.334375,106.667187 L693.334375,153.334375 C693.334375,161.334375 698.667188,166.667188 706.667188,166.667188 C714.667188,166.667188 720,161.334375 720,153.334375 L720,93.334375 C720,85.334375 714.667188,80.0015625 706.667188,80.0015625 L646.667188,80.0015625 C638.667188,80.0015625 633.334375,85.334375 633.334375,93.334375 C633.334375,101.334375 638.667188,106.667187 646.667188,106.667187 Z" id="Path"></path>
|
||||
<path d="M706.667188,229.332812 C698.667188,229.332812 693.334375,234.665625 693.334375,242.665625 L693.334375,377.332812 C693.334375,385.332812 698.667188,390.665625 706.667188,390.665625 C714.667188,390.665625 720,383.998437 720,377.332812 L720,242.665625 C720,234.667188 714.667188,229.332812 706.667188,229.332812 Z" id="Path"></path>
|
||||
<path d="M706.667187,453.332812 C698.667187,453.332812 693.334375,458.665625 693.334375,466.665625 L693.334375,517.332813 L648.001562,542.665625 C641.334375,546.665625 638.66875,554.665625 642.66875,561.332813 C645.335938,565.332813 649.335938,568 654.66875,568 C656.001562,568 658.66875,568 661.335938,568 L713.335937,538.667188 C717.335937,536 720.003125,532 720.003125,526.667188 L720.003125,466.667188 C720,458.667188 714.667187,453.332812 706.667187,453.332812 Z" id="Path"></path>
|
||||
<path d="M498.667187,641.332812 C501.334375,645.332812 505.334375,648 510.667187,648 C512,648 514.667187,646.667187 517.334375,646.667187 L604.001562,598.667187 C610.66875,594.667187 613.334375,586.667187 609.334375,580 C605.334375,573.332812 597.334375,570.667187 590.667187,574.667187 L504,622.667187 C497.332812,626.667187 494.667187,634.667187 498.667187,641.332812 Z" id="Path"></path>
|
||||
<path d="M336,658.667188 C332,665.334375 334.667188,673.334375 341.332813,677.334375 L393.332813,706.667188 C396,708 397.332813,708 400,708 C402.667188,708 404,708 406.667188,706.667188 L460,678.667188 C466.667188,674.667188 469.332813,666.667188 465.332813,660 C461.332813,653.332813 453.332813,650.667188 446.665625,654.667188 L400,680 L354.667188,653.332813 C348,649.332813 340,652 336,658.667188 Z" id="Path"></path>
|
||||
<path d="M196,598.667187 L282.667187,646.667187 C285.334375,648 286.667187,648 289.334375,648 C294.667187,648 298.667187,645.332813 301.334375,641.332813 C305.334375,634.665625 302.667187,626.665625 296.001562,622.665625 L209.334375,574.665625 C202.667187,570.665625 194.667187,573.332812 190.667187,579.998437 C186.667187,586.664062 189.332812,594.667187 196,598.667187 Z" id="Path"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.4 KiB |
98
services/apple/Shared (App)/HotPocket 27.icon/icon.json
Normal file
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"fill-specializations" : [
|
||||
{
|
||||
"value" : {
|
||||
"linear-gradient" : [
|
||||
"display-p3:0.30588,0.37647,0.40784,1.00000",
|
||||
"srgb:0.19608,0.27451,0.31373,1.00000"
|
||||
],
|
||||
"orientation" : {
|
||||
"start" : {
|
||||
"x" : 0.5,
|
||||
"y" : 0
|
||||
},
|
||||
"stop" : {
|
||||
"x" : 0.5,
|
||||
"y" : 0.7
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"value" : {
|
||||
"linear-gradient" : [
|
||||
"display-p3:0.18824,0.18824,0.18824,1.00000",
|
||||
"srgb:0.07451,0.07451,0.07451,1.00000"
|
||||
],
|
||||
"orientation" : {
|
||||
"start" : {
|
||||
"x" : 0.5,
|
||||
"y" : 0
|
||||
},
|
||||
"stop" : {
|
||||
"x" : 0.5,
|
||||
"y" : 0.7
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"image-name" : "pepper 2.svg",
|
||||
"name" : "pepper 2"
|
||||
}
|
||||
],
|
||||
"lighting" : "individual",
|
||||
"shadow" : {
|
||||
"kind" : "none",
|
||||
"opacity" : 0.5
|
||||
},
|
||||
"specular" : true,
|
||||
"translucency" : {
|
||||
"enabled" : true,
|
||||
"value" : 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"glass-specializations" : [
|
||||
{
|
||||
"value" : false
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"value" : false
|
||||
}
|
||||
],
|
||||
"image-name" : "pocket 2.svg",
|
||||
"name" : "pocket 2"
|
||||
}
|
||||
],
|
||||
"shadow" : {
|
||||
"kind" : "layer-color",
|
||||
"opacity" : 0.25
|
||||
},
|
||||
"specular-specializations" : [
|
||||
{
|
||||
"value" : false
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"value" : false
|
||||
}
|
||||
],
|
||||
"translucency" : {
|
||||
"enabled" : true,
|
||||
"value" : 0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"supported-platforms" : {
|
||||
"squares" : "shared"
|
||||
}
|
||||
}
|
||||
21
services/apple/Shared (App)/NSBundle+HotPocketExtensions.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// NSBundle+HotPocketExtensions.h
|
||||
// HotPocket
|
||||
//
|
||||
// Created by Tomek Wójcik on 17/11/2025.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSBundle (HotPocketExtensions)
|
||||
|
||||
+(NSString *)uname;
|
||||
+(NSDictionary *)postAuthenticateURLParams;
|
||||
+(NSString *)postAuthenticateURLScheme;
|
||||
+(NSString *)postAuthenticateURLHost;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
36
services/apple/Shared (App)/NSBundle+HotPocketExtensions.m
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// NSBundle+HotPocketExtensions.m
|
||||
// HotPocket
|
||||
//
|
||||
// Created by Tomek Wójcik on 17/11/2025.
|
||||
//
|
||||
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
|
||||
@implementation NSBundle (HotPocketExtensions)
|
||||
|
||||
+(NSString *)uname {
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
return [NSString stringWithFormat:@"HotPocket v%@ (%@)", [mainBundle.infoDictionary valueForKey:@"CFBundleShortVersionString"], [mainBundle.infoDictionary valueForKey:@"CFBundleVersion"]];
|
||||
}
|
||||
|
||||
+(NSDictionary *)postAuthenticateURLParams {
|
||||
NSDictionary *result = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"HPAuthFlowPostAuthenticateURLParts"];
|
||||
if (result == nil) {
|
||||
return [NSDictionary dictionary];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+(NSString *)postAuthenticateURLScheme {
|
||||
NSDictionary *params = [self postAuthenticateURLParams];
|
||||
return [params valueForKey:@"scheme"];
|
||||
}
|
||||
|
||||
+(NSString *)postAuthenticateURLHost {
|
||||
NSDictionary *params = [self postAuthenticateURLParams];
|
||||
return [params valueForKey:@"host"];
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
services/apple/Shared (App)/Resources/icon-glass-512.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 68 KiB |
@@ -5,10 +5,10 @@
|
||||
// Created by Tomek Wójcik on 21/08/2025.
|
||||
//
|
||||
|
||||
#import "SafariWebExtensionHandler.h"
|
||||
|
||||
#import <SafariServices/SafariServices.h>
|
||||
|
||||
#import "SafariWebExtensionHandler.h"
|
||||
|
||||
@implementation SafariWebExtensionHandler
|
||||
|
||||
- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context {
|
||||
|
||||
@@ -6,12 +6,19 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AuthenticationServices/AuthenticationServices.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AuthorizationProgressViewController : UIViewController
|
||||
@class MultilineLabel;
|
||||
|
||||
@interface AuthorizationProgressViewController : UIViewController<ASWebAuthenticationPresentationContextProviding>
|
||||
|
||||
@property IBOutlet UIActivityIndicatorView *progressIndicator;
|
||||
@property IBOutlet MultilineLabel *progressLabel;
|
||||
@property (strong, nullable) NSURL *authorizationURL;
|
||||
@property (strong, nullable) ASWebAuthenticationSession *webAuthenticationSession;
|
||||
@property BOOL userCancelledSession;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -8,20 +8,36 @@
|
||||
#import "AuthorizationProgressViewController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "HPAuthFlow.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "MultilineLabel.h"
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
|
||||
@interface AuthorizationProgressViewController (AuthorizationProgressViewControllerPrivate)
|
||||
|
||||
#pragma mark - Private interface
|
||||
|
||||
-(void)presentAuthorizationError;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AuthorizationProgressViewController
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
-(instancetype)initWithCoder:(NSCoder *)coder {
|
||||
if (self = [super initWithCoder:coder]) {
|
||||
self.authorizationURL = nil;
|
||||
self.webAuthenticationSession = nil;
|
||||
self.userCancelledSession = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.progressLabel.text = NSLocalizedString(@"Continue to sign in in your browser...", @"Continue to sign in in your browser...");
|
||||
}
|
||||
|
||||
-(void)viewWillAppear:(BOOL)animated {
|
||||
@@ -29,29 +45,74 @@
|
||||
[self.progressIndicator startAnimating];
|
||||
|
||||
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAuthFlowDidFinish:) name:@"AuthFlowDidFinish" object:appDelegate.authFlow];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onAuthFlowDidFinish:)
|
||||
name:@"AuthFlowDidFinish"
|
||||
object:appDelegate.authFlow];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onAuthFlowDidReceiveAuthParams:)
|
||||
name:@"AuthFlowDidReceiveAuthParams"
|
||||
object:appDelegate.authFlow];
|
||||
}
|
||||
|
||||
-(void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
-(void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
|
||||
|
||||
ASWebAuthenticationSessionCompletionHandler completionHandler = ^(NSURL *url, NSError *error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error != nil) {
|
||||
#ifdef DEBUG
|
||||
NSLog(@"[AuthorizationViewController.session completionHandler] error=`%@`", error);
|
||||
#endif
|
||||
if (error.code == ASWebAuthenticationSessionErrorCodeCanceledLogin) {
|
||||
self.userCancelledSession = YES;
|
||||
}
|
||||
[self presentAuthorizationError];
|
||||
} else {
|
||||
HPAuthParams *receivedAuthParams = [appDelegate.authFlow handlePostAuthenticateURL:url];
|
||||
if (receivedAuthParams != nil) {
|
||||
[appDelegate.authFlow handleAuthParams:receivedAuthParams];
|
||||
} else {
|
||||
[self presentAuthorizationError];
|
||||
}
|
||||
}
|
||||
|
||||
self.webAuthenticationSession = nil;
|
||||
});
|
||||
};
|
||||
|
||||
ASWebAuthenticationSessionCallback *callback = [ASWebAuthenticationSessionCallback callbackWithCustomScheme:[NSBundle postAuthenticateURLScheme]];
|
||||
self.webAuthenticationSession = [[ASWebAuthenticationSession alloc] initWithURL:self.authorizationURL
|
||||
callback:callback
|
||||
completionHandler:completionHandler];
|
||||
self.webAuthenticationSession.presentationContextProvider = self;
|
||||
#ifdef DEBUG
|
||||
self.webAuthenticationSession.prefersEphemeralWebBrowserSession = YES;
|
||||
#endif
|
||||
|
||||
if (self.webAuthenticationSession.canStart == NO) {
|
||||
[self presentAuthorizationError];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.webAuthenticationSession start];
|
||||
}
|
||||
|
||||
-(void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
self.webAuthenticationSession = nil;
|
||||
|
||||
[self.progressIndicator stopAnimating];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - Notification handlers
|
||||
# pragma mark - Private interface
|
||||
|
||||
-(void)onAuthFlowDidFinish:(NSNotification *)notification {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#ifdef DEBUG
|
||||
NSLog(@"-[AuthorizationViewController onAuthFlowDidFinish:] notification=`%@`", notification);
|
||||
#endif
|
||||
HPCredentials *credentials = [[HPCredentialsHelper sharedHelper] getCredentials];
|
||||
|
||||
if (credentials.usable == NO) {
|
||||
-(void)presentAuthorizationError {
|
||||
if (self.userCancelledSession == NO) {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Oops!", @"Oops!")
|
||||
message:NSLocalizedString(@"HotPocket couldn't complete this operation.", @"HotPocket couldn't complete this operation.")
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
@@ -65,10 +126,36 @@
|
||||
}]];
|
||||
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
} else {
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Notification handlers
|
||||
|
||||
-(void)onAuthFlowDidFinish:(NSNotification *)notification {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#ifdef DEBUG
|
||||
NSLog(@"-[AuthorizationViewController onAuthFlowDidFinish:] notification=`%@`", notification);
|
||||
#endif
|
||||
HPCredentials *credentials = [[HPCredentialsHelper sharedHelper] getCredentials];
|
||||
|
||||
if (credentials.usable == NO) {
|
||||
[self presentAuthorizationError];
|
||||
} else {
|
||||
[self.navigationController popToRootViewControllerAnimated:YES];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
-(void)onAuthFlowDidReceiveAuthParams:(NSNotification *)notification {
|
||||
self.progressLabel.text = NSLocalizedString(@"Processing authorization...", @"Processing authorization...");
|
||||
}
|
||||
|
||||
# pragma mark - ASWebAuthenticationPresentationContextProviding implementation
|
||||
|
||||
-(ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session {
|
||||
return self.view.window;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class UnameLabel;
|
||||
|
||||
@interface AuthorizationViewController : UIViewController
|
||||
|
||||
@property UIImageView *invalidURLWarningView;
|
||||
|
||||
@property IBOutlet UITextField *instanceURLField;
|
||||
@property IBOutlet UnameLabel *unameLabel;
|
||||
|
||||
-(IBAction)doStartAuthorizationFlow:(id)sender;
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
#import "HPAuthFlow.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "MainViewController.h"
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
#import "NSURL+HotPocketExtensions.h"
|
||||
#import "UnameLabel.h"
|
||||
|
||||
@interface AuthorizationViewController (AuthorizationViewControllerPrivate)
|
||||
|
||||
@@ -31,6 +33,8 @@
|
||||
self.invalidURLWarningView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
self.invalidURLWarningView.frame = CGRectMake(0, 0, 16, 16);
|
||||
self.invalidURLWarningView.tintColor = [UIColor colorNamed:@"WarningColor"];
|
||||
|
||||
self.unameLabel.text = [NSBundle uname];
|
||||
}
|
||||
|
||||
-(void)viewWillAppear:(BOOL)animated {
|
||||
@@ -69,14 +73,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if ([application canOpenURL:authURL] == YES) {
|
||||
[application openURL:authURL options:@{} completionHandler:^(BOOL result) {
|
||||
if (result == YES) {
|
||||
AuthorizationProgressViewController *authorizationProgressViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"AuthorizationProgressViewController"];
|
||||
authorizationProgressViewController.authorizationURL = authURL;
|
||||
[self.navigationController pushViewController:authorizationProgressViewController animated:YES];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Event handlers
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24127" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24063"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||
<capability name="Image references" minToolsVersion="12.0"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
@@ -24,7 +24,7 @@
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6HG-Um-bch">
|
||||
<rect key="frame" x="116" y="0.0" width="128" height="128"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<imageReference key="image" image="icon-mac-384.png"/>
|
||||
<imageReference key="image" image="icon-glass-512.png"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="HotPocket by BTHLabs" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="v6f-dw-6WO">
|
||||
<rect key="frame" x="0.0" y="136" width="361" height="29"/>
|
||||
@@ -46,7 +46,7 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="icon-mac-384.png" width="384" height="384"/>
|
||||
<image name="icon-glass-512.png" width="630" height="630"/>
|
||||
<namedColor name="BackgroundColor">
|
||||
<color red="0.12941176470588237" green="0.14509803921568629" blue="0.16078431372549021" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24127" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="7Sa-RR-xgc">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="7Sa-RR-xgc">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24063"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||
<capability name="Image references" minToolsVersion="12.0"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
@@ -77,6 +77,13 @@
|
||||
<action selector="doLogOut:" destination="BYZ-38-t0r" eventType="primaryActionTriggered" id="iq7-wK-GMu"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SD4-ZJ-wLU" userLabel="uname Label" customClass="UnameLabel">
|
||||
<rect key="frame" x="20" y="855" width="374" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" name="BackgroundColor"/>
|
||||
@@ -86,6 +93,7 @@
|
||||
<connections>
|
||||
<outlet property="instanceURLButton" destination="OPO-AY-zgd" id="1Wr-H9-eZ6"/>
|
||||
<outlet property="logoutButton" destination="wQZ-n6-b0o" id="vco-vP-zvy"/>
|
||||
<outlet property="unameLabel" destination="SD4-ZJ-wLU" id="LLk-wO-epu"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
@@ -136,7 +144,7 @@
|
||||
<action selector="doStartAuthorizationFlow:" destination="1Il-xJ-X5Y" eventType="primaryActionTriggered" id="Rd9-1f-N6Z"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Enter the URL to your HotPocket instance, e.g. https://my.hotpocket.app" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tn1-fl-daL" customClass="MultilineLabel">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Enter the URL to your HotPocket instance, e.g. https://hotpocket.yourcompany.com/" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Tn1-fl-daL" customClass="MultilineLabel">
|
||||
<rect key="frame" x="20" y="348" width="374" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
@@ -152,6 +160,13 @@
|
||||
<action selector="doStartAuthorizationFlow:" destination="1Il-xJ-X5Y" eventType="primaryActionTriggered" id="U0V-Pp-M2x"/>
|
||||
</connections>
|
||||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gId-nt-VtS" userLabel="uname Label" customClass="UnameLabel">
|
||||
<rect key="frame" x="20" y="855" width="374" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="dL2-4T-yXY"/>
|
||||
<color key="backgroundColor" name="BackgroundColor"/>
|
||||
@@ -159,6 +174,7 @@
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="instanceURLField" destination="v5s-Uh-qWU" id="hRQ-r8-3Dz"/>
|
||||
<outlet property="unameLabel" destination="gId-nt-VtS" id="ust-gO-7YN"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="m6b-Bm-Ty7" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
@@ -213,8 +229,8 @@
|
||||
<rect key="frame" x="189" y="306" width="37" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Awaiting authentication response..." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qiJ-yx-nMd">
|
||||
<rect key="frame" x="20" y="359" width="374" height="21"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Awaiting authentication response..." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qiJ-yx-nMd" customClass="MultilineLabel">
|
||||
<rect key="frame" x="20" y="359" width="374" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
@@ -226,6 +242,7 @@
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="progressIndicator" destination="DNy-gf-n60" id="hJF-jc-ZJ0"/>
|
||||
<outlet property="progressLabel" destination="qiJ-yx-nMd" id="1Wu-em-XsK"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="N3D-cM-5Ro" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
|
||||
@@ -9,10 +9,13 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class UnameLabel;
|
||||
|
||||
@interface MainViewController : UIViewController
|
||||
|
||||
@property IBOutlet UIButton *instanceURLButton;
|
||||
@property IBOutlet UIButton *logoutButton;
|
||||
@property IBOutlet UnameLabel *unameLabel;
|
||||
|
||||
-(IBAction)doOpenInstanceURL:(id)sender;
|
||||
-(IBAction)doLogOut:(id)sender;
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
|
||||
#import "MainViewController.h"
|
||||
|
||||
#import "HPCredentialsHelper.h"
|
||||
|
||||
#import "AuthorizationViewController.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
#import "UnameLabel.h"
|
||||
|
||||
@interface MainViewController (MainViewControllerPrivate)
|
||||
|
||||
@@ -27,6 +28,8 @@
|
||||
[self.instanceURLButton setTitle:@"" forState:UIControlStateNormal];
|
||||
self.instanceURLButton.enabled = NO;
|
||||
|
||||
self.unameLabel.text = [NSBundle uname];
|
||||
|
||||
self.logoutButton.enabled = NO;
|
||||
}
|
||||
|
||||
|
||||
16
services/apple/iOS (App)/UnameLabel.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// UnameLabel.h
|
||||
// HotPocket
|
||||
//
|
||||
// Created by Tomek Wójcik on 17/11/2025.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UnameLabel : UILabel
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
16
services/apple/iOS (App)/UnameLabel.m
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// UnameLabel.m
|
||||
// HotPocket
|
||||
//
|
||||
// Created by Tomek Wójcik on 17/11/2025.
|
||||
//
|
||||
|
||||
#import "UnameLabel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation UnameLabel
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24127" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24063"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||
<capability name="Image references" minToolsVersion="12.0"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
@@ -44,8 +44,8 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CqC-1V-R49">
|
||||
<rect key="frame" x="138" y="107" width="77" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<rect key="frame" x="130" y="107" width="92" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" title="Button"/>
|
||||
<buttonConfiguration key="configuration" style="gray" title="Cancel">
|
||||
<color key="baseForegroundColor" name="DangerColor"/>
|
||||
@@ -57,7 +57,7 @@
|
||||
</subviews>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9Dr-s7-Kqv" userLabel="Done View">
|
||||
<rect key="frame" x="20" y="299" width="353" height="142"/>
|
||||
<rect key="frame" x="20" y="299" width="353" height="193"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="checkmark.circle.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="0oo-rV-Vfd">
|
||||
@@ -73,9 +73,9 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AHS-eb-Mk8">
|
||||
<rect key="frame" x="143" y="107" width="67" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="AccentColor"/>
|
||||
<rect key="frame" x="132" y="107" width="88" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="SecondaryColor"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<buttonConfiguration key="configuration" style="tinted" title="Close"/>
|
||||
@@ -102,9 +102,9 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gFP-1G-Hef">
|
||||
<rect key="frame" x="143" y="107" width="67" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="AccentColor"/>
|
||||
<rect key="frame" x="130" y="107" width="92" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="SecondaryColor"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<buttonConfiguration key="configuration" style="tinted" title="Close"/>
|
||||
@@ -131,9 +131,9 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UJs-K5-SJe">
|
||||
<rect key="frame" x="143" y="107" width="67" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="AccentColor"/>
|
||||
<rect key="frame" x="130" y="107" width="92" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="SecondaryColor"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<buttonConfiguration key="configuration" style="tinted" title="Close"/>
|
||||
@@ -161,8 +161,8 @@
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0WL-Hk-6Bk">
|
||||
<rect key="frame" x="143" y="107" width="67" height="35"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="AccentColor"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="tintColor" name="SecondaryColor"/>
|
||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
|
||||
<state key="normal" title="Close"/>
|
||||
<buttonConfiguration key="configuration" style="tinted" title="Close"/>
|
||||
@@ -189,6 +189,7 @@
|
||||
<outlet property="errorView" destination="DLn-U6-UcA" id="cl1-I0-nY1"/>
|
||||
<outlet property="needsSetupView" destination="eqK-cv-2mf" id="Vb3-Y3-8Y8"/>
|
||||
<outlet property="progressIndicator" destination="1HO-hL-WcQ" id="1Qd-Gt-b3G"/>
|
||||
<outlet property="savedLabel" destination="QoY-OC-nmX" id="cqW-iq-7CR"/>
|
||||
<outlet property="savingView" destination="zdu-vr-R6t" id="svY-bA-Z9d"/>
|
||||
<outlet property="unameLabel" destination="xfn-uj-KNk" id="TTp-PV-ttr"/>
|
||||
<outlet property="unprocessableEntityView" destination="ckY-6z-0fe" id="owN-qJ-oBj"/>
|
||||
@@ -204,14 +205,14 @@
|
||||
<image name="exclamationmark.circle.fill" catalog="system" width="128" height="123"/>
|
||||
<image name="icon-mac-384.png" width="384" height="384"/>
|
||||
<image name="multiply.circle.fill" catalog="system" width="128" height="123"/>
|
||||
<namedColor name="AccentColor">
|
||||
<color red="0.10980392156862745" green="0.72941176470588232" blue="0.92941176470588238" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="BackgroundColor">
|
||||
<color red="0.12941176470588237" green="0.14509803921568629" blue="0.16078431372549021" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="DangerColor">
|
||||
<color red="0.93300002813339233" green="0.3919999897480011" blue="0.46299999952316284" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.93333333333333335" green="0.39215686274509803" blue="0.46274509803921571" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="SecondaryColor">
|
||||
<color red="0.0" green="0.50980392156862742" blue="0.8666666666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="SuccessColor">
|
||||
<color red="0.054901960784313725" green="0.65490196078431373" blue="0.40392156862745099" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class HPAPI;
|
||||
@class UnameLabel;
|
||||
|
||||
@interface ShareViewController : UIViewController
|
||||
|
||||
@@ -19,7 +20,8 @@
|
||||
@property IBOutlet UIView *doneView;
|
||||
@property IBOutlet UIView *errorView;
|
||||
@property IBOutlet UIView *unprocessableEntityView;
|
||||
@property IBOutlet UILabel *unameLabel;
|
||||
@property IBOutlet UnameLabel *unameLabel;
|
||||
@property IBOutlet UILabel *savedLabel;
|
||||
|
||||
-(IBAction)doCancel:(id)sender;
|
||||
-(IBAction)doClose:(id)sender;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#import "HPAPI.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "HPShareExtensionHelper.h"
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
#import "UnameLabel.h"
|
||||
|
||||
@implementation ShareViewController (ShareViewControllerPrivate)
|
||||
|
||||
@@ -31,6 +33,21 @@
|
||||
#endif
|
||||
self.errorView.hidden = NO;
|
||||
} else {
|
||||
self.savedLabel.text = NSLocalizedString(
|
||||
@"Your link has been saved!",
|
||||
@"Your link has been saved!"
|
||||
);
|
||||
|
||||
NSDictionary *save = result.result;
|
||||
|
||||
BOOL isNetlocBanned = [(NSNumber *)[save valueForKey:@"is_netloc_banned"] boolValue];
|
||||
if (isNetlocBanned == YES) {
|
||||
self.savedLabel.text = NSLocalizedString(
|
||||
@"Your link has been saved, but you may want to update its title.",
|
||||
@"Your link has been saved, but you may want to update its title."
|
||||
);
|
||||
}
|
||||
|
||||
self.doneView.hidden = NO;
|
||||
}
|
||||
});
|
||||
@@ -68,8 +85,7 @@
|
||||
self.errorView.hidden = YES;
|
||||
self.unprocessableEntityView.hidden = YES;
|
||||
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
self.unameLabel.text = [NSString stringWithFormat:@"HotPocket v%@ (%@)", [mainBundle.infoDictionary valueForKey:@"CFBundleShortVersionString"], [mainBundle.infoDictionary valueForKey:@"CFBundleVersion"]];
|
||||
self.unameLabel.text = [NSBundle uname];
|
||||
|
||||
self.api = [[HPAPI alloc] init];
|
||||
if (self.api.rpcClient.hasCredentials == YES) {
|
||||
|
||||
@@ -21,18 +21,6 @@
|
||||
}
|
||||
|
||||
-(void)application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)urls {
|
||||
HPAuthParams *receivedAuthParams = nil;
|
||||
for (NSURL *url in urls) {
|
||||
receivedAuthParams = [self.authFlow handlePostAuthenticateURL:url];
|
||||
|
||||
if (receivedAuthParams != nil) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (receivedAuthParams != nil) {
|
||||
[self.authFlow handleAuthParams:receivedAuthParams];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -6,12 +6,19 @@
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <AuthenticationServices/AuthenticationServices.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AuthorizationProgressViewController : NSViewController
|
||||
@interface AuthorizationProgressViewController : NSViewController<ASWebAuthenticationPresentationContextProviding>
|
||||
|
||||
@property IBOutlet NSProgressIndicator *progressIndicator;
|
||||
@property NSString *progressLabelTitle;
|
||||
@property (nullable, strong) NSURL *authorizationURL;
|
||||
@property (nullable, strong) ASWebAuthenticationSession *webAuthenticationSession;
|
||||
@property BOOL userCancelledSession;
|
||||
|
||||
-(IBAction)doCancel:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -9,37 +9,133 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "AuthorizationViewController.h"
|
||||
#import "HPAuthFlow.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "MainViewController.h"
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
#import "ReplaceAnimator.h"
|
||||
|
||||
@interface AuthorizationProgressViewController (AuthorizationProgressViewControllerPrivate)
|
||||
|
||||
#pragma mark - Private interface
|
||||
|
||||
-(void)presentAuthorizationError;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AuthorizationProgressViewController
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
-(instancetype)initWithCoder:(NSCoder *)coder {
|
||||
if (self = [super initWithCoder:coder]) {
|
||||
self.authorizationURL = nil;
|
||||
self.webAuthenticationSession = nil;
|
||||
self.userCancelledSession = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.progressLabelTitle = NSLocalizedString(@"Continue to sign in in your browser...", @"Continue to sign in in your browser...");
|
||||
}
|
||||
|
||||
-(void)viewWillAppear {
|
||||
AppDelegate *appDelegate = [[NSApplication sharedApplication] delegate];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAuthFlowDidFinish:) name:@"AuthFlowDidFinish" object:appDelegate.authFlow];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onAuthFlowDidFinish:)
|
||||
name:@"AuthFlowDidFinish"
|
||||
object:appDelegate.authFlow];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onAuthFlowDidReceiveAuthParams:)
|
||||
name:@"AuthFlowDidReceiveAuthParams"
|
||||
object:appDelegate.authFlow];
|
||||
|
||||
[self.progressIndicator startAnimation:self];
|
||||
}
|
||||
|
||||
-(void)viewDidAppear {
|
||||
[super viewDidAppear];
|
||||
AppDelegate *appDelegate = [[NSApplication sharedApplication] delegate];
|
||||
|
||||
ASWebAuthenticationSessionCompletionHandler completionHandler = ^(NSURL *url, NSError *error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error != nil) {
|
||||
#ifdef DEBUG
|
||||
NSLog(@"[AuthorizationViewController.session completionHandler] error=`%@`", error);
|
||||
#endif
|
||||
if (error.code == ASWebAuthenticationSessionErrorCodeCanceledLogin) {
|
||||
self.userCancelledSession = YES;
|
||||
}
|
||||
[self presentAuthorizationError];
|
||||
} else {
|
||||
HPAuthParams *receivedAuthParams = [appDelegate.authFlow handlePostAuthenticateURL:url];
|
||||
if (receivedAuthParams != nil) {
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
[appDelegate.authFlow handleAuthParams:receivedAuthParams];
|
||||
} else {
|
||||
[self presentAuthorizationError];
|
||||
}
|
||||
}
|
||||
|
||||
self.webAuthenticationSession = nil;
|
||||
});
|
||||
};
|
||||
|
||||
ASWebAuthenticationSessionCallback *callback = [ASWebAuthenticationSessionCallback callbackWithCustomScheme:[NSBundle postAuthenticateURLScheme]];
|
||||
self.webAuthenticationSession = [[ASWebAuthenticationSession alloc] initWithURL:self.authorizationURL
|
||||
callback:callback
|
||||
completionHandler:completionHandler];
|
||||
self.webAuthenticationSession.presentationContextProvider = self;
|
||||
#ifdef DEBUG
|
||||
self.webAuthenticationSession.prefersEphemeralWebBrowserSession = YES;
|
||||
#endif
|
||||
|
||||
if (self.webAuthenticationSession.canStart == NO) {
|
||||
[self presentAuthorizationError];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.webAuthenticationSession start];
|
||||
}
|
||||
|
||||
-(void)viewDidDisappear {
|
||||
[super viewDidDisappear];
|
||||
self.webAuthenticationSession = nil;
|
||||
|
||||
[self.progressIndicator stopAnimation:self];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
-(IBAction)doCancel:(id)sender {
|
||||
[self.webAuthenticationSession cancel];
|
||||
}
|
||||
|
||||
#pragma mark - Private interface
|
||||
|
||||
-(void)presentAuthorizationError {
|
||||
if (self.userCancelledSession == NO) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
alert.alertStyle = NSAlertStyleCritical;
|
||||
alert.messageText = NSLocalizedString(@"Oops!", @"Oops!");
|
||||
alert.informativeText = NSLocalizedString(@"HotPocket couldn't complete this operation.", @"HotPocket couldn't complete this operation.");
|
||||
[alert beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse response) {
|
||||
AuthorizationViewController *authorizationViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationViewController"];
|
||||
[self presentViewController:authorizationViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
}];
|
||||
} else {
|
||||
AuthorizationViewController *authorizationViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationViewController"];
|
||||
[self presentViewController:authorizationViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Notification handlers
|
||||
|
||||
-(void)onAuthFlowDidFinish:(NSNotification *)notification {
|
||||
@@ -50,14 +146,7 @@
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
|
||||
if (credentials.usable == NO) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
alert.alertStyle = NSAlertStyleCritical;
|
||||
alert.messageText = NSLocalizedString(@"Oops!", @"Oops!");
|
||||
alert.informativeText = NSLocalizedString(@"HotPocket couldn't complete this operation.", @"HotPocket couldn't complete this operation.");
|
||||
[alert runModal];
|
||||
|
||||
AuthorizationViewController *authorizationViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationViewController"];
|
||||
[self presentViewController:authorizationViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
[self presentAuthorizationError];
|
||||
} else {
|
||||
MainViewController *mainViewController = [self.storyboard instantiateControllerWithIdentifier:@"MainViewController"];
|
||||
[self presentViewController:mainViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
@@ -65,4 +154,14 @@
|
||||
});
|
||||
}
|
||||
|
||||
-(void)onAuthFlowDidReceiveAuthParams:(NSNotification *)notification {
|
||||
self.progressLabelTitle = NSLocalizedString(@"Processing authorization...", @"Processing authorization...");
|
||||
}
|
||||
|
||||
# pragma mark - ASWebAuthenticationPresentationContextProviding implementation
|
||||
|
||||
-(ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session {
|
||||
return self.view.window;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#import "AuthorizationViewController.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "HPAuthFlow.h"
|
||||
#import "AuthorizationProgressViewController.h"
|
||||
#import "HPAuthFlow.h"
|
||||
#import "ReplaceAnimator.h"
|
||||
|
||||
@interface AuthorizationViewController (AuthorizationViewControllerPrivate)
|
||||
@@ -31,19 +31,24 @@
|
||||
#pragma mark - Actions
|
||||
|
||||
-(IBAction)doStartAuthorizationFlow:(id)sender {
|
||||
AppDelegate *appDeleate = [[NSApplication sharedApplication] delegate];
|
||||
appDeleate.authFlow.baseURL = [NSURL URLWithString:self.baseURL];
|
||||
AppDelegate *appDelegate = [[NSApplication sharedApplication] delegate];
|
||||
appDelegate.authFlow.baseURL = [NSURL URLWithString:self.baseURL];
|
||||
|
||||
NSURL *authURL = [appDeleate.authFlow start];
|
||||
NSURL *authURL = [appDelegate.authFlow start];
|
||||
if (authURL == nil) {
|
||||
NSBeep();
|
||||
return;
|
||||
}
|
||||
|
||||
AuthorizationProgressViewController *authProgressViewController = [self.storyboard instantiateControllerWithIdentifier:@"AuthorizationProgressViewController"];
|
||||
authProgressViewController.authorizationURL = authURL;
|
||||
[self presentViewController:authProgressViewController animator:[[ReplaceAnimator alloc] init]];
|
||||
}
|
||||
|
||||
[[NSWorkspace sharedWorkspace] openURL:authURL];
|
||||
# pragma mark - ASWebAuthenticationPresentationContextProviding implementation
|
||||
|
||||
-(ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session {
|
||||
return self.view.window;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="24127" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24127"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24506"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -103,7 +103,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7sM-F3-Zzf">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7sM-F3-Zzf">
|
||||
<rect key="frame" x="18" y="153" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="HotPocket Instance URL" id="XwM-DV-kei">
|
||||
@@ -112,7 +112,7 @@
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ygC-xe-m6y">
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ygC-xe-m6y">
|
||||
<rect key="frame" x="20" y="124" width="385" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="rHK-hP-yWO">
|
||||
@@ -128,10 +128,10 @@
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DIc-8O-uoQ">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DIc-8O-uoQ">
|
||||
<rect key="frame" x="18" y="68" width="389" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="Enter the URL to your HotPocket instance, e.g. https://my.hotpocket.app" id="Y0q-a1-oBP">
|
||||
<textFieldCell key="cell" selectable="YES" title="Enter the URL to your HotPocket instance, e.g. https://hotpocket.yourcompany.com/" id="Y0q-a1-oBP">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -140,7 +140,7 @@
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PAH-U3-ltl">
|
||||
<rect key="frame" x="180" y="221" width="64" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon-mac-384" id="jnV-K2-7gf"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon-glass-512" id="jnV-K2-7gf"/>
|
||||
</imageView>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Zr-9i-XDS">
|
||||
<rect key="frame" x="13" y="33" width="89" height="32"/>
|
||||
@@ -154,7 +154,7 @@
|
||||
<action selector="doStartAuthorizationFlow:" target="XfG-lQ-9wD" id="AOi-Wt-gmL"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mQc-Ea-NNN">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mQc-Ea-NNN">
|
||||
<rect key="frame" x="18" y="185" width="389" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="HotPocket by BTHLabs" id="NTZ-zl-yhk">
|
||||
@@ -177,7 +177,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="325"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yRj-hC-QYS">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yRj-hC-QYS">
|
||||
<rect key="frame" x="18" y="185" width="389" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="HotPocket by BTHLabs" id="F4l-2Z-D79">
|
||||
@@ -195,15 +195,32 @@
|
||||
<rect key="frame" x="196" y="113" width="32" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</progressIndicator>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="g9a-gR-c7o">
|
||||
<rect key="frame" x="18" y="81" width="389" height="16"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="g9a-gR-c7o">
|
||||
<rect key="frame" x="18" y="49" width="389" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Awaiting authorization response..." id="3oi-LK-vKv">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="OX4-Oj-1cw" name="value" keyPath="self.progressLabelTitle" id="ydU-jy-p3F"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Sip-bU-V5i">
|
||||
<rect key="frame" x="175" y="14" width="76" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="nYJ-LO-V7O">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
Gw
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="doCancel:" target="OX4-Oj-1cw" id="nAC-If-aib"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</view>
|
||||
<connections>
|
||||
@@ -227,7 +244,7 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="icon-mac-384" id="fae-mz-0sj"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T7q-KB-3Ut">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T7q-KB-3Ut">
|
||||
<rect key="frame" x="18" y="185" width="389" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="HotPocket by BTHLabs" id="r5O-Sk-IdK">
|
||||
@@ -236,7 +253,7 @@
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2h7-bN-dsa">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2h7-bN-dsa">
|
||||
<rect key="frame" x="18" y="153" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="HotPocket is configured and ready." id="5fh-mh-WR1">
|
||||
@@ -245,7 +262,7 @@
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uci-UC-wxo">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uci-UC-wxo">
|
||||
<rect key="frame" x="18" y="89" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Instance URL" id="azk-ea-KeN">
|
||||
@@ -267,8 +284,8 @@
|
||||
<binding destination="r5D-xE-cNT" name="enabled" keyPath="self.logoutButtonEnabled" id="gTs-BO-USz"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8H3-oU-acU" customClass="LinkLabel">
|
||||
<rect key="frame" x="18" y="65" width="389" height="16"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8H3-oU-acU" customClass="LinkLabel">
|
||||
<rect key="frame" x="18" y="69" width="389" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" allowsEditingTextAttributes="YES" id="EoA-mM-phM">
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -276,7 +293,7 @@
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9pl-Ap-yxc">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9pl-Ap-yxc">
|
||||
<rect key="frame" x="18" y="113" width="389" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="Safari and Share Extensions are installed." id="dy7-bw-DYh">
|
||||
@@ -297,6 +314,7 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="icon-glass-512" width="630" height="630"/>
|
||||
<image name="icon-mac-384" width="384" height="384"/>
|
||||
<namedColor name="AccentColor">
|
||||
<color red="0.10980392156862745" green="0.72941176470588232" blue="0.92941176470588238" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
#import "MainViewController.h"
|
||||
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "AuthorizationViewController.h"
|
||||
#import "HPCredentialsHelper.h"
|
||||
#import "ReplaceAnimator.h"
|
||||
|
||||
@interface MainViewController (MainViewControllerPrivate)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24127" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24127"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24506"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -23,7 +23,7 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyDown" image="icon-mac-384" id="NT0-XU-t9f"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KZW-gY-pvX">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KZW-gY-pvX">
|
||||
<rect key="frame" x="18" y="138" width="352" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="HotPocket by BTHLabs" id="urI-Z1-yMm">
|
||||
@@ -50,7 +50,7 @@ Gw
|
||||
<action selector="cancel:" target="-2" id="yRt-GR-jQ6"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5X8-4n-wWm">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5X8-4n-wWm">
|
||||
<rect key="frame" x="-2" y="28" width="352" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" alignment="center" title="HotPocket couldn't complete this operation." id="fmg-RT-3FA">
|
||||
@@ -94,7 +94,7 @@ Gw
|
||||
<action selector="close:" target="-2" id="3aP-Lu-EzX"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Mfx-pW-oi2">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Mfx-pW-oi2">
|
||||
<rect key="frame" x="-2" y="28" width="352" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" alignment="center" title="Your link has been saved!" id="JhJ-K4-UFb">
|
||||
@@ -102,6 +102,9 @@ Gw
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="self.savedLabelText" id="l2G-Uh-L0d"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<connections>
|
||||
@@ -118,7 +121,7 @@ Gw
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyUpOrDown" image="exclamationmark.circle.fill" catalog="system" id="3kO-Gq-csg"/>
|
||||
<color key="contentTintColor" name="WarningColor"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YLC-Bx-qKZ">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YLC-Bx-qKZ">
|
||||
<rect key="frame" x="-2" y="28" width="352" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" alignment="center" title="Open the HotPocket application to set it up." id="eYb-eq-cbo">
|
||||
@@ -183,7 +186,7 @@ Gw
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageScaling="proportionallyUpOrDown" image="exclamationmark.circle.fill" catalog="system" id="66K-cT-2Vw"/>
|
||||
<color key="contentTintColor" name="WarningColor"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LS4-qN-h75">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LS4-qN-h75">
|
||||
<rect key="frame" x="-2" y="28" width="352" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" alignment="center" title="This item couldn't be shared :(." id="b0i-Lf-21f">
|
||||
@@ -211,7 +214,7 @@ Gw
|
||||
<binding destination="-2" name="hidden" keyPath="self.unprocessableEntityViewHidden" id="lqC-lO-ll8"/>
|
||||
</connections>
|
||||
</customView>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1yJ-sU-Spr" userLabel="uname Label">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1yJ-sU-Spr" userLabel="uname Label">
|
||||
<rect key="frame" x="6" y="4" width="376" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" id="nQ0-Es-oIB">
|
||||
@@ -233,7 +236,7 @@ Gw
|
||||
<image name="icon-mac-384" width="384" height="384"/>
|
||||
<image name="multiply.circle.fill" catalog="system" width="15" height="15"/>
|
||||
<namedColor name="DangerColor">
|
||||
<color red="0.93300002813339233" green="0.3919999897480011" blue="0.46299999952316284" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color red="0.93333333333333335" green="0.39215686274509803" blue="0.46274509803921571" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
<namedColor name="SuccessColor">
|
||||
<color red="0.054901960784313725" green="0.65490196078431373" blue="0.40392156862745099" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
@property BOOL errorViewHidden;
|
||||
@property BOOL unprocessableEntityViewHidden;
|
||||
@property NSString *uname;
|
||||
@property NSString *savedLabelText;
|
||||
|
||||
@property IBOutlet NSProgressIndicator *progressIndicator;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#import "HPAPI.h"
|
||||
#import "HPShareExtensionHelper.h"
|
||||
#import "NSBundle+HotPocketExtensions.h"
|
||||
|
||||
@implementation ShareViewController (ShareViewControllerPrivate)
|
||||
|
||||
@@ -28,6 +29,21 @@
|
||||
#endif
|
||||
self.errorViewHidden = NO;
|
||||
} else {
|
||||
self.savedLabelText = NSLocalizedString(
|
||||
@"Your link has been saved!",
|
||||
@"Your link has been saved!"
|
||||
);
|
||||
|
||||
NSDictionary *save = result.result;
|
||||
|
||||
BOOL isNetlocBanned = [(NSNumber *)[save valueForKey:@"is_netloc_banned"] boolValue];
|
||||
if (isNetlocBanned == YES) {
|
||||
self.savedLabelText = NSLocalizedString(
|
||||
@"Your link has been saved, but you may want to update its title.",
|
||||
@"Your link has been saved, but you may want to update its title."
|
||||
);
|
||||
}
|
||||
|
||||
self.doneViewHidden = NO;
|
||||
}
|
||||
});
|
||||
@@ -69,8 +85,11 @@
|
||||
self.errorViewHidden = YES;
|
||||
self.unprocessableEntityViewHidden = YES;
|
||||
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
self.uname = [NSString stringWithFormat:@"HotPocket v%@ (%@)", [mainBundle.infoDictionary valueForKey:@"CFBundleShortVersionString"], [mainBundle.infoDictionary valueForKey:@"CFBundleVersion"]];
|
||||
self.uname = [NSBundle uname];
|
||||
self.savedLabelText = NSLocalizedString(
|
||||
@"Your link has been saved!",
|
||||
@"Your link has been saved!"
|
||||
);
|
||||
|
||||
self.api = [[HPAPI alloc] init];
|
||||
if (self.api.rpcClient.hasCredentials == YES) {
|
||||
|
||||
458
services/apple/poetry.lock
generated
@@ -1,5 +1,72 @@
|
||||
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "ast-serialize"
|
||||
version = "0.8.0"
|
||||
description = "Python bindings for mypy AST serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:3d822605fa7bb326ef868d25fafced7fc660fa46d9b90c02ea86d5e2f5d325f7"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:2efa40b068197d5efb62655b43baadb842ed71c4958cccd3e8b86a35726f0119"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:db1b957291bca08c7e72f43a12357b2948e20775d970e3fc3dac0aa3160ab725"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdc0d5b18ff8fb364e87923e47c0a91d0d69dbcaeaa274591f7fd26892cc3a3a"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9da7330f3e235bf7da89b8d39205c6350fc0c08a85379743f2df9fff87d6d980"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3186969ee66a9863b00acc6523ace44c56974eecb348a7ea4b228d9f0b80e19"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40a57b73731be45da4fa41430c4d5dc94a24b3a4faba7b9e069978c0402064ea"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5075b9da3ef807eda752502446dfecea3b381c4900b7e27a5d5f4f899eb39951"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:293cc1c5bfa741f8e3fbe8175b9c07beee487c9a6fdbb25a5acad9f1df2d30a9"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0910c3442a75216dde0f102d854ba2aaa71d2482e0ee213630b9bf29584fba3"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43dd6d596879bb1cb8a12cc9dae7bb10090a39a35883026c24f82488a195619a"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8c9d537f59e936392cfd3597789d1390304dd659efc3c486ce7f40fb6b8a9f53"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f0190a33d7f97c65e9069f7a7f40499eea6b5cbe260c558378109caf20ce934b"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:77308ae6c5cf5264cc0f01a7c556ec77a9e68eb1f61b093534d698139fdc3b14"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8d53a23f27e1ed3a36b2d26fd2a1a6228c8e85a1ed62ff7cdb44bd610769f20a"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa5e7cb08f96fed9121f77b224151e41caf88feab9d652bb46c78202b6fbeda"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-win32.whl", hash = "sha256:fa70ed4dea0bb18b30a1789c77baa701d0ef30c474f2ccabdea61e25623a8827"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d8b3c8eee4c1baef9d4e84d2a59a805501617127be42615cb48970b15b0892b6"},
|
||||
{file = "ast_serialize-0.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:ac4f0a83c55a9b782f79ad55a5247b7db123c1db405959791c2ef886e9710c9f"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-macosx_10_12_x86_64.whl", hash = "sha256:86b8a1e6d90467345356098b040150e82fbc26d24a7a202224b13dc1f6264ca0"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-macosx_11_0_arm64.whl", hash = "sha256:39e92ff8e8cb45947fe9007174b2950e1fb098e6abd00266a13cd3bcf6675068"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c85d8d18db5b2dfcb3b7e38a4d600ca35504c0ed8a6f75cd1c811e4ffe248a15"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9830ff7e764f74d9eefb01170c61a9f0fd2c027dac5fcb72e064decd57d56371"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6479d9722a4cd21b578f5478074c41e6169f04811996ec881655560f703a5bba"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a63bed264e818cd83eec11feed0f50aa162542b91132ef58afebc857182763a5"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d187197d234aa45d6cfa2b096be5f666e8cc2e7eb3722d0ab8926293cf5720c"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_31_riscv64.whl", hash = "sha256:2d39a56282cfcc0d8eeea37267c754be59c98d48505c23b1dae5c6011f3813dd"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7cc5f10386994c0f4844f1e6d6a97127e9b478660eb6dec2b257644f0acab64"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:6102f2f985c2e542be85cd857678ec9356fefa792b93cadfadd31139f5696f27"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_armv7l.whl", hash = "sha256:3a8660fe66667b76a6e9dccd1d33e66b229fde3b308db991c041609226c005b6"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_i686.whl", hash = "sha256:e7266307e5fba39836edb79def8608887af48820508bff3c5f2941e1e04d1534"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca7e6fd1ad845d1cc649dc2ecd499db2f8f46af5bf8da7b70dd858774cc038b"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_riscv64.whl", hash = "sha256:2880350b13d3eae69a0d70bc1fb6c9bfaca4dbd0e20ba8cd1aa483080b56ff06"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-musllinux_1_2_x86_64.whl", hash = "sha256:ab0f9a59f7d63d0d441b56b9a818b273705264352d5115cfee12e940e816d958"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-win32.whl", hash = "sha256:0485a25ef519c62e749ee3c1ad8070e591b380d67226349eb5a70b228dc1ac4a"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-win_amd64.whl", hash = "sha256:bd84d60bca7079e741be4ac5dbe237751a59d7f6f9f0126b11880d63822cbe16"},
|
||||
{file = "ast_serialize-0.8.0-cp315-abi3.abi3t-win_arm64.whl", hash = "sha256:057769b5921336eb2d9124f2a731b42ed05ffdac559b840dbdf6f3937cf153dc"},
|
||||
{file = "ast_serialize-0.8.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:a02cbed7d8bfdcdee88edaac12bd50d53d9953aaa2e1852ef078625be5f1c0b5"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e1bd223df0f6c96b396975fa604cb33bce53d9b4a0185490be4c4a289f7c9c87"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ddd3b61f45c132da66c5476b281891e08c1fd87fbdabe8a6973e1622efc85f06"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f9caa63fad8241257ae401b5ff0a64026c6adb36b8e86cbe8782d9ea505daf6"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3926fa117b5e65019853a2969966d11c7175af377a3425991f3fe73784412405"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:485f1113af805e9e170b95ef993ca3fbd4f89c04bab25c58b4fc632d854801ab"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccebbed24f1281062d5852353c72c47502955926cfcb8345ffb3a44d87ff3d3"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:252f883290d1cdb728eb7fe1d9a7221b88af5a329aae0bc91ddee4dafb820331"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:96abc072ad29db8d02194afd47d68987322622787daceae82398d7b69f3ba2e6"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9118ad3e369727060b2696fc4078f250ecffca4248ba87f537f55cea9f9dce06"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f359df4bd921918af8bebd142a376c77511d7151cc8ba852760b587b5a4a54f3"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:e94f9121d13fa36cbf21314783c77d05ae3a0868decd18cf5233fdcc6de49ac8"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:54f95b486018d262bcb387a9afd96f0da74508b442762b80c769454a6fbb3ee3"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4c38b915511e32bc718c49dbce98ff9af36bac0ad6a604f58000cd5e3aecdba7"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:9a2ef9cf12f2de4f1028c42c1dd7d775255e0fb3e5bb48896c97e35ef52366fe"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f18048fe9f6dd266bd577cdec48bdcecb74faaa01fe941324435483b013ed2a"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-win32.whl", hash = "sha256:31883542dd6c94d178f5db3d32fbd69c5eb88b3a7c018e7ac8cc0c45195ddbed"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-win_amd64.whl", hash = "sha256:861794565b06337005c1447ef23103a3d5a627d08bdc827870d00d0b28ef5f51"},
|
||||
{file = "ast_serialize-0.8.0-cp39-abi3-win_arm64.whl", hash = "sha256:b2a5978662fd4db463dfb4b974d2b10ac6430b98f5333aabc7051909df3561d0"},
|
||||
{file = "ast_serialize-0.8.0.tar.gz", hash = "sha256:6c37c43e4004dfb42d321ddedc569dc17ff4259296f3af577c9ea46a809bc010"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asttokens"
|
||||
version = "3.0.0"
|
||||
@@ -56,40 +123,6 @@ files = [
|
||||
[package.extras]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
|
||||
|
||||
[[package]]
|
||||
name = "factory-boy"
|
||||
version = "3.3.3"
|
||||
description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "factory_boy-3.3.3-py2.py3-none-any.whl", hash = "sha256:1c39e3289f7e667c4285433f305f8d506efc2fe9c73aaea4151ebd5cdea394fc"},
|
||||
{file = "factory_boy-3.3.3.tar.gz", hash = "sha256:866862d226128dfac7f2b4160287e899daf54f2612778327dd03d0e2cb1e3d03"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
Faker = ">=0.7.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["Django", "Pillow", "SQLAlchemy", "coverage", "flake8", "isort", "mongoengine", "mongomock", "mypy", "tox", "wheel (>=0.32.0)", "zest.releaser[recommended]"]
|
||||
doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"]
|
||||
|
||||
[[package]]
|
||||
name = "faker"
|
||||
version = "37.11.0"
|
||||
description = "Faker is a Python package that generates fake data for you."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "faker-37.11.0-py3-none-any.whl", hash = "sha256:1508d2da94dfd1e0087b36f386126d84f8583b3de19ac18e392a2831a6676c57"},
|
||||
{file = "faker-37.11.0.tar.gz", hash = "sha256:22969803849ba0618be8eee2dd01d0d9e2cd3b75e6ff1a291fa9abcdb34da5e6"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
tzdata = "*"
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "7.3.0"
|
||||
@@ -127,7 +160,7 @@ name = "hotpocket-workspace-tools"
|
||||
version = "1.0.0.dev0"
|
||||
description = "HotPocket Workspace Tools"
|
||||
optional = false
|
||||
python-versions = "^3.12"
|
||||
python-versions = "^3.13"
|
||||
groups = ["dev"]
|
||||
files = []
|
||||
develop = true
|
||||
@@ -169,35 +202,35 @@ ipython = {version = ">=7.31.1", markers = "python_version >= \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
version = "9.6.0"
|
||||
version = "9.16.1"
|
||||
description = "IPython: Productive Interactive Computing"
|
||||
optional = false
|
||||
python-versions = ">=3.11"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "ipython-9.6.0-py3-none-any.whl", hash = "sha256:5f77efafc886d2f023442479b8149e7d86547ad0a979e9da9f045d252f648196"},
|
||||
{file = "ipython-9.6.0.tar.gz", hash = "sha256:5603d6d5d356378be5043e69441a072b50a5b33b4503428c77b04cb8ce7bc731"},
|
||||
{file = "ipython-9.16.1-py3-none-any.whl", hash = "sha256:4acae635506f6d352d94c4899a19d5f85f8bc4d230932342dca556fdab1c69b4"},
|
||||
{file = "ipython-9.16.1.tar.gz", hash = "sha256:5a3d1f9a47ff216d6cf9cf863124f6a2c1a198d1354c546a4d24a370a283b64c"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
decorator = "*"
|
||||
ipython-pygments-lexers = "*"
|
||||
jedi = ">=0.16"
|
||||
matplotlib-inline = "*"
|
||||
pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""}
|
||||
colorama = {version = ">=0.4.4", markers = "sys_platform == \"win32\""}
|
||||
ipython-pygments-lexers = ">=1.0.0"
|
||||
jedi = ">=0.18.2"
|
||||
matplotlib-inline = ">=0.1.6"
|
||||
pexpect = {version = ">4.6", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""}
|
||||
prompt_toolkit = ">=3.0.41,<3.1.0"
|
||||
pygments = ">=2.4.0"
|
||||
stack_data = "*"
|
||||
psutil = {version = ">=7", markers = "sys_platform != \"emscripten\" and sys_platform != \"cygwin\""}
|
||||
pygments = ">=2.14.0"
|
||||
stack_data = ">=0.6.0"
|
||||
traitlets = ">=5.13.0"
|
||||
|
||||
[package.extras]
|
||||
all = ["ipython[doc,matplotlib,test,test-extra]"]
|
||||
all = ["argcomplete (>=3.0)", "ipython[doc,matplotlib,test,test-extra]"]
|
||||
black = ["black"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[matplotlib,test]", "setuptools (>=61.2)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"]
|
||||
matplotlib = ["matplotlib (>3.7)"]
|
||||
test = ["packaging", "pytest", "pytest-asyncio", "testpath"]
|
||||
test-extra = ["curio", "ipykernel", "ipython[matplotlib]", "ipython[test]", "jupyter_ai", "nbclient", "nbformat", "numpy (>=1.25)", "pandas (>2.0)", "trio"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[matplotlib,test]", "setuptools (>=80.0)", "sphinx (>=8.0)", "sphinx-rtd-theme (>=0.1.8)", "sphinx_toml (==0.0.4)", "typing_extensions"]
|
||||
matplotlib = ["matplotlib (>3.9)"]
|
||||
test = ["packaging (>=23.0.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=1.0.0)", "setuptools (>=80.0)", "testpath (>=0.2)"]
|
||||
test-extra = ["curio", "ipykernel (>6.30)", "ipython[matplotlib]", "ipython[test]", "jupyter_ai", "nbclient", "nbformat", "numpy (>=2.0)", "pandas (>2.1)", "trio (>=0.22.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "ipython-pygments-lexers"
|
||||
@@ -216,19 +249,18 @@ pygments = "*"
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "7.0.0"
|
||||
version = "8.0.1"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
optional = false
|
||||
python-versions = ">=3.10.0"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1"},
|
||||
{file = "isort-7.0.0.tar.gz", hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187"},
|
||||
{file = "isort-8.0.1-py3-none-any.whl", hash = "sha256:28b89bc70f751b559aeca209e6120393d43fbe2490de0559662be7a9787e3d75"},
|
||||
{file = "isort-8.0.1.tar.gz", hash = "sha256:171ac4ff559cdc060bcfff550bc8404a486fee0caab245679c2abe7cb253c78d"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
colors = ["colorama"]
|
||||
plugins = ["setuptools"]
|
||||
|
||||
[[package]]
|
||||
name = "jedi"
|
||||
@@ -250,6 +282,154 @@ docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alab
|
||||
qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"]
|
||||
testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "librt"
|
||||
version = "0.15.0"
|
||||
description = "Mypyc runtime library"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
markers = "platform_python_implementation != \"PyPy\""
|
||||
files = [
|
||||
{file = "librt-0.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1a49adf16a7c9d9646816c2946135527197b6fcf4347c7b8b761cf1bfbf4489"},
|
||||
{file = "librt-0.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81a398f45b45a59200e13cd5ad1ae1d3f44334de98b148331afe2cdfee701c52"},
|
||||
{file = "librt-0.15.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4eafbaff06b9563f8b1c850621ce51605de05208e09d4d71ce490bc972b7b9e8"},
|
||||
{file = "librt-0.15.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b0411b4066db926b80258c60dcb0e6db4c9cee312eab45b7e8866b17ddf9ada1"},
|
||||
{file = "librt-0.15.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:febb1ce6cac545a54e6b769982824e955a700fdd9fbf3a08a3d82c990968b57d"},
|
||||
{file = "librt-0.15.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b230acc1c3bfe2d6f2627ba2b95dc92e58aa494600e9722d0e6ccbc931e59702"},
|
||||
{file = "librt-0.15.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6da110e5f314c19ab8478464d02ae18808ae73d522c15260fa4918acdcd64da9"},
|
||||
{file = "librt-0.15.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:eab9208b00ca55bf75983ec99f7bf13acc746a36102e98953addaad7f7ea1e1b"},
|
||||
{file = "librt-0.15.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6c013cd3a1721e69e14380ada97eaa4b7b0cdf1c6b96fa765d4ea47c875088db"},
|
||||
{file = "librt-0.15.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:567b1c430f8bd560e689421468278ac5941bab4a05303b5d95b6ae10db03f451"},
|
||||
{file = "librt-0.15.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:29c4cab9df457b19672c39be7f384ebb2bc925c4e2684b8780c222b43eb36389"},
|
||||
{file = "librt-0.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bccbd8e5b0bffb7106cf18eb1baa3d7194b1cebb3b4b1cdbd4bdb19382a6ee6c"},
|
||||
{file = "librt-0.15.0-cp310-cp310-win32.whl", hash = "sha256:8ae493ed5f659a7761c43d42f183db514536073ded9bcf671d2d1df47e29a07e"},
|
||||
{file = "librt-0.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc25fb356d0c7810bb49ff3df908ad1fda6995d660ab099ded69244ed7ab6053"},
|
||||
{file = "librt-0.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:823b92cf3c18ecd08afc70c42473888b41b6e8ef5046f3b82c05c154a2fa3d22"},
|
||||
{file = "librt-0.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c70bc1b602cf59917e8f0c7a2cbc8bcc6fbc14d5486136b00707a79619121d63"},
|
||||
{file = "librt-0.15.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:814ff83a25b5fce8b9c80c4dd803153fb5c5599fc74db9e022466938368957ef"},
|
||||
{file = "librt-0.15.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:57f5eeb6ad4c180de583b1038e61fe5fbd9796bb69a8a1c1a0c7ddbec4c8c60f"},
|
||||
{file = "librt-0.15.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82909c8f7eb9952656b65d3147afde4cf8e6d5a991eebc86418b5e65843b0ab8"},
|
||||
{file = "librt-0.15.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f779070399f991400fc451719e0ea388eb7de313388bada2c127a35de05f798a"},
|
||||
{file = "librt-0.15.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bac89069bc496ebdf4f79ebb57bbd10d0b214c8454225deb672d91002bd17e18"},
|
||||
{file = "librt-0.15.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e0d00c708fb2f5822b152429b1ac80a58dbbbc3f6c232c4d13a3f7fcf2ea5b4c"},
|
||||
{file = "librt-0.15.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6c6624fe268625869485553dd7cc1daf30d22558215bb2a4ff16f67a9801a31a"},
|
||||
{file = "librt-0.15.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f56b397858a23dacf35ede366ed2212fdc03a6a57a1ad36468ad6e9dc5fac091"},
|
||||
{file = "librt-0.15.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4388184646efe2054911c5b00a1077d6d1ee86a95b7e8ba96dc7850a809f3f40"},
|
||||
{file = "librt-0.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97335f59082f9fe2ce6c2a9cc6433a0114bbb6cd4d5c09dd76c95c68b9f9a8b0"},
|
||||
{file = "librt-0.15.0-cp311-cp311-win32.whl", hash = "sha256:83380ffde38062a2e9bb55d83e74474f6614665528b98a6928720fc006dfffbb"},
|
||||
{file = "librt-0.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:f75720477ee05d509a310e856cacc8d909adc182f7b91193c207bcc26d7ee6db"},
|
||||
{file = "librt-0.15.0-cp311-cp311-win_arm64.whl", hash = "sha256:256237037a3ab001ae8d9803b2d43562a4c3aa38739843694349e4d5ebb0fd56"},
|
||||
{file = "librt-0.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e87bc679f86a99aa3b26e3c78eeb821a247c9a28eae48eaafcc32c3bf4c3bb9e"},
|
||||
{file = "librt-0.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71599e011ac880e8e45d46047d714871894c7d4ab6f25626f8d4f89da21f368d"},
|
||||
{file = "librt-0.15.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c802434092b769b1d613ed2e13fac15fbfce1934a74bd10283b03c0fae231cd1"},
|
||||
{file = "librt-0.15.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5500eeae393a184d14e1f35645962c27129d20c81afa4069e6ef826ebc2b3aaa"},
|
||||
{file = "librt-0.15.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6ecfc32dfb46fb7b565bcd6abf9412acf978775a998273d22888a6d7953730dd"},
|
||||
{file = "librt-0.15.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cc46cfd15022e35084355478c9ac809d90b1152222706ac9a7655ec21df6fa"},
|
||||
{file = "librt-0.15.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5f51401d102c885b9ca509e62c79b1dbff286e1b9b047fde6f763780789356d"},
|
||||
{file = "librt-0.15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cc30523e3f1a23fb7511cc659834a0d01a1042bb9de359bc1c131cc4ec6c9656"},
|
||||
{file = "librt-0.15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:59fe030d8ae4a57e3fb7756bf35a858de74e04066fc8555c53d0af979132af81"},
|
||||
{file = "librt-0.15.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a6526a2a956bbb1e4ae3568c82e650fc99119c66bb011ea60715744955a2b4d"},
|
||||
{file = "librt-0.15.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:85ea21ec6730194d67156b0e0b5430ccb1d61f8b8b907e39b37f9812b74a13f0"},
|
||||
{file = "librt-0.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1e47b8ba865d7ede071a91a7163073bbaeb72541f1ef8a07d512c45c7b5007f2"},
|
||||
{file = "librt-0.15.0-cp312-cp312-win32.whl", hash = "sha256:a5207ec414d1c4a2a7231b2086970dc036f94293cdf338190984958a013a42f1"},
|
||||
{file = "librt-0.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:73b30cfa976659b3917c8f6153bdb0591c6a9ec6583599fd24a689b690622022"},
|
||||
{file = "librt-0.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:a54cf9e0ef47b96af580849db5471142200568ce1e02cbf416addab551369570"},
|
||||
{file = "librt-0.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:db13ca398005abcbe538deda87b686d9bd08b7001cf40c4c06b444960ae10a26"},
|
||||
{file = "librt-0.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa1f1995789dca3698bc550aaceb09a51bd5df0a057ff84ff15296cd1975b801"},
|
||||
{file = "librt-0.15.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55456ea87d8df21808446d03817be2f65e20391c1c615d9187440dff28cd08dc"},
|
||||
{file = "librt-0.15.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5a86a5a08c2235316bdb359d5dbb6ce0abfca7fac06363103e2c5af571d92f95"},
|
||||
{file = "librt-0.15.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e56b6a368529bed262da40ce13f8fef590db0479819cca84f16a1f01ac356d0b"},
|
||||
{file = "librt-0.15.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:234d8d394721fa0d786af15ebf1f3fb7f3ed82fd1cd0cde45c2f247b5d4281d2"},
|
||||
{file = "librt-0.15.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d8363d7accb0286ac3a0e633f396e93800dafb8150494505daf9515bbda591f3"},
|
||||
{file = "librt-0.15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0f0ee3644d951f31055ad07d77d92520e84505dd7a432cc4cd501dd70ee06785"},
|
||||
{file = "librt-0.15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cfd1a81a648806e6a7717be4cc4d1bb392fa229752bf8444ba365e381e984d6"},
|
||||
{file = "librt-0.15.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6cd22c9da0d866558e46a041f1cc0c2bbb26b61b137b2347fa834c332e1d101"},
|
||||
{file = "librt-0.15.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6d5225ef8801e4ea5e482fa9b5dfb891dd9ef6f6d870f1f25d449ca2c70ac218"},
|
||||
{file = "librt-0.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d28a05796b99f749bf8794f17ba9ba1612d0076b802e9cfc62c554634e9ce3b"},
|
||||
{file = "librt-0.15.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:2067ff438048cead9d223ca5675bae2a25e520a7c3e6c1498bf9c6892d22caab"},
|
||||
{file = "librt-0.15.0-cp313-cp313-win32.whl", hash = "sha256:1cd3b721f24c206398b9e26da3c3a9c011e6e89d06f318ba8ebefc30f1003890"},
|
||||
{file = "librt-0.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:f395a4a9a03ac062dbe9a9f82e0c720502e590a38feee6a757bc82e9c63afbd8"},
|
||||
{file = "librt-0.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:0a15cb554761247d84a3ec0cbdf4078d70725384f0e4662c0fa3b26266eb60ad"},
|
||||
{file = "librt-0.15.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f5de7feedc56337a088eb15cd9fafa9938367362221d8cc62c642b7f94821993"},
|
||||
{file = "librt-0.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c0eb900c0e91f4aebe680845242e614f1864edfd44106380d0752ac29522bf8"},
|
||||
{file = "librt-0.15.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e8c9a650a188e38bac005048cbe6342e81407782944d01934540ab75e417df21"},
|
||||
{file = "librt-0.15.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:92bfed8deec93df30286b9fe9e3b1dd17329cc076a192b4ee5ec223841d54953"},
|
||||
{file = "librt-0.15.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ec4b19788f835711a2072f9dbe6b03b3bf32ed1f0fb30cf399bdd59d9f0c33fa"},
|
||||
{file = "librt-0.15.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4c7bacb70930f3d0a56f4ecf1be474a1f0d941b01dd73b756f3c256d42cb879"},
|
||||
{file = "librt-0.15.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3e79f05e4a08b4d880342673312bbc895b56df7765605796f15902eb5367d3ae"},
|
||||
{file = "librt-0.15.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a417149c0cba4d50b61e992e5a15e69eaf96746609b461cc4ed168aeef6b79dd"},
|
||||
{file = "librt-0.15.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:da7a94d6a3411f579d72aa3e3bc5fbca7ed4549f3dbd7e5de3aa567333374285"},
|
||||
{file = "librt-0.15.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:856f743ae607f2c1380eccb566c0038a9fb3eabf0fc2be2704d76d9f73557239"},
|
||||
{file = "librt-0.15.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:779a6e7c894737e5983e7790a9c78c4000c30e23c9aada08081bdbea53b0fa60"},
|
||||
{file = "librt-0.15.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:96bb17dbe8bab3c0954fbebfc69ed395599de75b6bbc35e3270a878e15d4dd65"},
|
||||
{file = "librt-0.15.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:7220697efaa6e5348fc3d18ee7f8563d4bfecd9872b37ffb915bfc1d08840622"},
|
||||
{file = "librt-0.15.0-cp314-cp314-win32.whl", hash = "sha256:f54598964d357b1c5ab77cf5d92f21e598fe0e23cdbe9618480807f81b4eba15"},
|
||||
{file = "librt-0.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ff5893a2c23d886aa9ce786de5ac6ddc74aeeaf90743682b74d920e117d2e28"},
|
||||
{file = "librt-0.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:3722a099730704c9a3d70c879fc0f51daec25fe5f1555672d97bc595abeafb95"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:38c0c7d4b6fc06c3324b3f9162c8391bfc4fd9dde53afe1033ce7edb48d5a714"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8b2fdd7ead3c995c37940a790690660d0ca006c302db26cc51933f6766866fc3"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2fde98cf1fc4bac144ce23c2c4c017b924ba714509ea9334977b0b27050c837d"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:e3b461183c5fa7681b48560f91515f53a953122fb30c71e07abc67d7ddf58c38"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4bbcc257e3babea20a91715c361b24554ec4e8f51aa578568afc230799fe1a19"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b845b8d48088fad0cadc84be4b8fda63203be7e9237b71015b3925443c1f35ab"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b30e600e8f337b9bd7f39b86d9fdfedc73cc46e3d0f745931a23a234220bb7e2"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:64b0c8c35aa4c4ed79896359f3e0b285cbe4e610042106500da4811c322cc108"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0da0d94cb802f32a0524653e7201f2cef72d5f700a5407678f5290483d4fcd08"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:4a6369168d371207339b1e50d4532b06a7121586141f82599505a3f315751d47"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c434e072557ade9cbc642d052c89d031efe47d5c9614523619d0d74a02378e81"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7eec6a42018bc1d45763b1c162d3d2bf7c3b9a1b0ed30d3e91dcba390efefcc"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-win32.whl", hash = "sha256:6912fa5e635d74529ac7cdb1bdf6ca3af4453da8d1edbe0110ee1cb4ad407ebf"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8e11699ed745931c395acd3621b07062e0f840efa6935aad87a64ed0995f0915"},
|
||||
{file = "librt-0.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:5d2a91724463bfed4f573cd7a9fdc856d2e230d0c0e5a61416a93481dccd8605"},
|
||||
{file = "librt-0.15.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:8443e38dcfcfdbcf5add5118c623efd788d65ac2e25756d6251a54a06a4d0aca"},
|
||||
{file = "librt-0.15.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:6d15a29033c57490cfe2069097c6fc4049e4e65ffbb749be7dc453b7c4c68965"},
|
||||
{file = "librt-0.15.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d2c05c729b589e734c09578bf5964be48a911765484840d017bbc84f49d4c4ad"},
|
||||
{file = "librt-0.15.0-cp315-cp315-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:fa60887537e1d0cd2d9982269d33a709bf54b195cd2b9364fc0a758022af5bd9"},
|
||||
{file = "librt-0.15.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d8bc24219b24c0af375718942ab75e3544b2763085f40f965be4326734ae8328"},
|
||||
{file = "librt-0.15.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86a21a7bd3fe3a419512ef424cc1c020f6771d0b29cfddff36d1635a855e63f0"},
|
||||
{file = "librt-0.15.0-cp315-cp315-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dbab647e88d90b3167b91efe7091e248653688ed4337e4f90907a722c7361bb9"},
|
||||
{file = "librt-0.15.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:d8edcf6f550e918dca779c069b9e156385c60b406f99fc7641f32c52f7193659"},
|
||||
{file = "librt-0.15.0-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:8b62076030baa2d8b1501a46bf0e19c27a489aa90671c55665bff7887f7660b0"},
|
||||
{file = "librt-0.15.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:d00d20d1818e82a07a0ee0aa89a98b17ed7916b92441090b683719cb20a59b6d"},
|
||||
{file = "librt-0.15.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:4e6ee93fc3cf848dcbf0cce2eca73d8e7dcd0cc2b6df3a529d57750b30a4c55c"},
|
||||
{file = "librt-0.15.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:32896a0af72508ea979e0acb4e4c04cbeeae04938167950d535c83c45597167d"},
|
||||
{file = "librt-0.15.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:ec3ba415afaf951f6951b1dd16d3c8e4f540065fc382d7e70b823a79567ca374"},
|
||||
{file = "librt-0.15.0-cp315-cp315-win32.whl", hash = "sha256:d2813ba2503764f0450680c533d13df7cff9b49df1411062eded5f67db4195b9"},
|
||||
{file = "librt-0.15.0-cp315-cp315-win_amd64.whl", hash = "sha256:b87d67e33afaf265262f2a66db578284b88ee2e6fcd224579cb5c15518677ad8"},
|
||||
{file = "librt-0.15.0-cp315-cp315-win_arm64.whl", hash = "sha256:713bd7df21170b982e729e46870f31d6b437bd1a9b4648cffb529bd3c2ec5c4b"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:3de789c82752730f94782a5ee518baf9c05edf85733aeaf73bb6e518755cdf54"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:e0b5deec9a8664eb722c797241970fd4aa1894d25fda36a1ddac0f7407606bd6"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5563302a8359bc2295bb7084d1a8ed1519df96afb30eb2aa4e0bff7b54228988"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:22d6263b9d39d7bbb286fa791945646e3218f1be2d693e36fb630f1d0e59cd13"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:39ffd14646190c454f0d86e0d256b33f00a87a26ab410e619773b841d0e41416"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c47318cd3a61401452de11282242937e3e057c4fd3dbaf601e269d0928a06c0a"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a56a1d4f859a82ca5b99fc4b82c9b027b15e3c455c5cd99e7d0719f27bb20b6c"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:077471b3182db4e17c36ae91555f36a4d2c00080b267f749bcad34a478a9a302"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:411ca4d1b905b860ceba7570dd6717a71dedaddcc4b0f77ece710aa41ee11f8d"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:1256589e0b0adb31751d685a68bce29d73407ddf4ef05d4188f49d5dcf9566d9"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:f42b74a53e5f26a0ba0007411a7455b66c67ce4022a39cc1f56fc4efd65bcbab"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:291bf73caf78b9e88d6fae9bfd693207ff7d832e2fdbe2cf8e746bc13f5f892b"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-win32.whl", hash = "sha256:c16d15ee371643ab48dc8248a3e680ebbeca573a13af2c3dd0c985b142d77162"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-win_amd64.whl", hash = "sha256:dbd605739f228912dc49027cb764456b9757750bdc2b6b7773164db7096c6fd1"},
|
||||
{file = "librt-0.15.0-cp315-cp315t-win_arm64.whl", hash = "sha256:84d244b00604d17df3fc7736c327892d6bba66181254aa4087be807b6c342bdc"},
|
||||
{file = "librt-0.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0e2d0c0acf5b0ada7d045912b7cf787c21315c95b38b1fa939ef72d45d366b3d"},
|
||||
{file = "librt-0.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9ca190fe9edc0eb08eec558a509a16d28d91c35667b8f043cba40ed5e77a959"},
|
||||
{file = "librt-0.15.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80811e1c42386ea95c6fb30571d3250ad43d7863f883f787f70517f441150e59"},
|
||||
{file = "librt-0.15.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:88c2a17815c266e6d8180204ff62cb739ab869ada4a746d4c505331526ac58f1"},
|
||||
{file = "librt-0.15.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a5fa8f1f916988d0bf1afea005bda37f56ac41a18016e813ccf0097a8d460ca4"},
|
||||
{file = "librt-0.15.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:355e3a4c725225a14262004fc1872a552b9d3634b4f791a0dfc80804aafbfd55"},
|
||||
{file = "librt-0.15.0-cp39-cp39-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc1ed11c4ad0b91af24def2050f2840ea4567828e3dd058fbe608d982f6e5465"},
|
||||
{file = "librt-0.15.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1f4ef2e71db33df4309167ed7f1520c4fae5e611226e159fa9cf33f93e6ddb3d"},
|
||||
{file = "librt-0.15.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1a1a8cd430c7dd0c083f455cb1b328d7fc682b05c31b940906f7845bdff80881"},
|
||||
{file = "librt-0.15.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:04d5387b908676c0b8d5d2f5fb58373b4ea382d81f7a6f0fab8ea2a462bb4738"},
|
||||
{file = "librt-0.15.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:1172c6ad2a88b646e7fe3b480e3fac4ab4418b3443fd8a4061fdd531e0622fc7"},
|
||||
{file = "librt-0.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:52e8db01f603f5da0ca30987479acff98769382efc8e142fa3962395dcf3ffdb"},
|
||||
{file = "librt-0.15.0-cp39-cp39-win32.whl", hash = "sha256:e4c911f15a1652ca94ae9f1abd92e74cbb1b3597d2d92fdd556202f94e8cd455"},
|
||||
{file = "librt-0.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:68242379c9b65a582b6e97318a1e9fbd6d445e58954f2d437991c4804ab11578"},
|
||||
{file = "librt-0.15.0.tar.gz", hash = "sha256:4e66cbe84437497d951b799d3e1551291b6fb3d643820a7014b3655d57a59162"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib-inline"
|
||||
version = "0.1.7"
|
||||
@@ -279,56 +459,75 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.18.2"
|
||||
version = "2.3.1"
|
||||
description = "Optional static typing for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
python-versions = ">=3.10"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"},
|
||||
{file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"},
|
||||
{file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"},
|
||||
{file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"},
|
||||
{file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"},
|
||||
{file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"},
|
||||
{file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"},
|
||||
{file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"},
|
||||
{file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"},
|
||||
{file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"},
|
||||
{file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"},
|
||||
{file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"},
|
||||
{file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"},
|
||||
{file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"},
|
||||
{file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"},
|
||||
{file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"},
|
||||
{file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"},
|
||||
{file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"},
|
||||
{file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"},
|
||||
{file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"},
|
||||
{file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"},
|
||||
{file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"},
|
||||
{file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"},
|
||||
{file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"},
|
||||
{file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"},
|
||||
{file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"},
|
||||
{file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"},
|
||||
{file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"},
|
||||
{file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"},
|
||||
{file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"},
|
||||
{file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"},
|
||||
{file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"},
|
||||
{file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"},
|
||||
{file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"},
|
||||
{file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"},
|
||||
{file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"},
|
||||
{file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"},
|
||||
{file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"},
|
||||
{file = "mypy-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:57a936373fc690c43a8cd7e7e12a35148e4ec5aa7698ad7fc0a9f918bdc5be41"},
|
||||
{file = "mypy-2.3.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d00d769056bde2f4e69c175071eba45cfb44fa1ed92bdfbfe64a93e0543b0cf0"},
|
||||
{file = "mypy-2.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2166b29228835e1f88ff411e96639e6ca3c7fdde84b62ec211f70f86b4051167"},
|
||||
{file = "mypy-2.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:83d36c2924df7426333abe7faf4724a7e1aab0d9fd41625e81b4683034b80c13"},
|
||||
{file = "mypy-2.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:f12fdb70459d0060dea40b29e52163a961b156106d68d57882a6a9f648983a53"},
|
||||
{file = "mypy-2.3.1-cp310-cp310-win_arm64.whl", hash = "sha256:e099200a1b1b1223a4951f0a90cbff1b8c91b250ba599dab1f7217a628144d90"},
|
||||
{file = "mypy-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94f04929f1c44c35fb0061e912087edaf504acede963a4a7d00680bd089d8531"},
|
||||
{file = "mypy-2.3.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5d716048611e85ca9eefb2e1baa5d73ede389b5820ded260ea27c757d667af8"},
|
||||
{file = "mypy-2.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b091a455111214cb5c9d54a57b9618e9a49f9fe2a42e4e1ac86e9d104ed96ce8"},
|
||||
{file = "mypy-2.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df12e20c9efd614738c71b390007ecd0181125afc4ccafca04d78a1d2eed2c01"},
|
||||
{file = "mypy-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:52eaf3a155f35cf80b40220288c861eb45f14a2340c1f6cbfbdb0feff32879d1"},
|
||||
{file = "mypy-2.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:9b4eacbee8a69836c06eff6d0dd4e134a07c2b047755b30c08625fe214f322c6"},
|
||||
{file = "mypy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a32bbbb940af990d3be0b8af321c7b6815bb1b3b48142fe7459b9cc5f58959ff"},
|
||||
{file = "mypy-2.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff715e45b2231a8e85de1d163d1b42791e4d7aab8f5145f85fee1b710b735aff"},
|
||||
{file = "mypy-2.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:858fc57d3d91fa728e33e7ad71def60fc6272694607b306cd3292db53ae39080"},
|
||||
{file = "mypy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:851833db876e7b650f93719c74b7879a08e338979c96054fdfc3bfd90a486355"},
|
||||
{file = "mypy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:4c5095a327483591c94e0c8d3ef9e50d4ab1369b541eae007c1f23bc2a41f6bb"},
|
||||
{file = "mypy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:bbfe022634a2a195406bd469e888d2eaf193b02ba7e607391cd7640374aaae3b"},
|
||||
{file = "mypy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:114dff494000f18bd10d5d95d84b8567b26da60279ecbe838131841df20e635d"},
|
||||
{file = "mypy-2.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8637731bb5eee3671eb2c3200827aa3564ed8a9309ecee4d1afe77e6d031bdb"},
|
||||
{file = "mypy-2.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c80fbc405ed8020f5ff3802dc18cf060197bcdd3fbdd6a26ef2fd34dfdd5226"},
|
||||
{file = "mypy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:84081f538ce27375045c02e3d7f81bd11d853400621ae245d87ce7b6c420ec74"},
|
||||
{file = "mypy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:e9144ac16fde007096f9563eb2041b4433c2d705c4218edeb79e7e9d01035ee6"},
|
||||
{file = "mypy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:77ad9529e67dca28e511f5cd5671436584ce91f6d3bac159a353158187b986ac"},
|
||||
{file = "mypy-2.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:192abaedf75da1bc0b1cef104927e70ec49c1ef0031cc4825c7ee10a438ed24d"},
|
||||
{file = "mypy-2.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf678dffd16efcda2c15cbd30e9ecc0081388e29ea23687a88e686ed92638dc3"},
|
||||
{file = "mypy-2.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e036f06b41630f4c8a1d48f9ac6aa26acc65f8be089973f5519da643318f03f"},
|
||||
{file = "mypy-2.3.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:71af9c8a894e862b58e92abb08e53b05a384a1e5e5d6dc7cda59126211a53d82"},
|
||||
{file = "mypy-2.3.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:3c80cd23d85368bdd9f37d5231dfd97d35bcbf5bf41af96ef3a9b078ad1957f9"},
|
||||
{file = "mypy-2.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:4956f34d145e145562a0a0bf367f642bbc85c04ec2baf47ae015947c3169a85d"},
|
||||
{file = "mypy-2.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:cfb12e360242d23d91f5e978d94f58ea66acf5804c4fb6f2f794a20d4cb1b595"},
|
||||
{file = "mypy-2.3.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5f1c50bb05b64e2026b52867e8d21106f01313c744a2c4ecc34c90d12e8d6e2"},
|
||||
{file = "mypy-2.3.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:667196b352f4cf304ded4c10f90cfc179263a1acfb3cdcfa984bdfd340d498bc"},
|
||||
{file = "mypy-2.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b9c53e395c12cad2c6d4b67d5da7c6057638a132d85c08b73646b18f802a0045"},
|
||||
{file = "mypy-2.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:18162b128c3f9c703cd35f5537446900b0d21a2549aa7a95d21380d2ef643fb0"},
|
||||
{file = "mypy-2.3.1-cp314-cp314t-win_amd64.whl", hash = "sha256:30c0477d4aab7b7f39c8397dc877f2c96b9fe5588ec379f372c56eb63d599f63"},
|
||||
{file = "mypy-2.3.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6941ab3619377bc3f32ca02876b07d27f216f5201604b664d3937ea0fdd23bb4"},
|
||||
{file = "mypy-2.3.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:6f041a6de52c9217ca125e78ba0a335cb7fd98a1c0580978e49ab2b126f70b57"},
|
||||
{file = "mypy-2.3.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5159ae60f5dbc3a498af5ba8365505808ac8031bc63f9e00304ad545d40bdd9b"},
|
||||
{file = "mypy-2.3.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47a8a7a0a7f6f6e63995c0ac36fa0c07b127413fdc81f0439b7f3dccafd33561"},
|
||||
{file = "mypy-2.3.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2329c0501293d4e1f33bc15d04d6304d65a1cdda967ee93a05c1e681a3923133"},
|
||||
{file = "mypy-2.3.1-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:bb26deed807bdb0457cf3e3f1cd7c4a1cf9d66864eaf1b4a61e06805d4c6b1f9"},
|
||||
{file = "mypy-2.3.1-cp315-cp315-win_amd64.whl", hash = "sha256:375d7013876a8233b2d05be185bfa09f689696cd999ce8b1cfe6acac5c80e8a3"},
|
||||
{file = "mypy-2.3.1-cp315-cp315-win_arm64.whl", hash = "sha256:586b3612214cceabb3c0f588c97e7d1e535393f06a60e912e994f6b3ace97523"},
|
||||
{file = "mypy-2.3.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:ef0c6335cda9d807f8193d8ff6204a72bc909fa9882aacbca14f43cdb7188306"},
|
||||
{file = "mypy-2.3.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e598c8c66401d26b150872154a286e6d484cf2789c3bb28a7556806298423021"},
|
||||
{file = "mypy-2.3.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eda22fd4efa9dcd39331d1dede9b5b8b8a7fd69af07592e778433da98610d29e"},
|
||||
{file = "mypy-2.3.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:2a0ba2e57847849fb0d1fcdabb32786d223095ed8bc121dfe322bcdb3d9c46bc"},
|
||||
{file = "mypy-2.3.1-cp315-cp315t-win_amd64.whl", hash = "sha256:3f7e865dd51f235f60a2dbcd8728a1c095f5ca28f095d48a725b84cd935735c4"},
|
||||
{file = "mypy-2.3.1-cp315-cp315t-win_arm64.whl", hash = "sha256:8ad80807dc3ab8ea978b1b2b6e4a657194ace1d4ef03e0e731aff1abd517da29"},
|
||||
{file = "mypy-2.3.1-py3-none-any.whl", hash = "sha256:6ed5c7e3419083268e5c9258bd1c1ef91af44a9e89374dbcaf37b775716e72eb"},
|
||||
{file = "mypy-2.3.1.tar.gz", hash = "sha256:47c1b1207258513a9d93495f69c8be9de73916186f0e52703e8c461b7a623419"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
ast-serialize = ">=0.6.0,<1.0.0"
|
||||
librt = {version = ">=0.13.0", markers = "platform_python_implementation != \"PyPy\""}
|
||||
mypy_extensions = ">=1.0.0"
|
||||
pathspec = ">=0.9.0"
|
||||
typing_extensions = ">=4.6.0"
|
||||
pathspec = ">=1.0.0"
|
||||
typing_extensions = [
|
||||
{version = ">=4.6.0", markers = "python_version < \"3.15\""},
|
||||
{version = ">=4.14.0", markers = "python_version >= \"3.15\""},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
@@ -367,16 +566,21 @@ testing = ["docopt", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.12.1"
|
||||
version = "1.1.1"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
|
||||
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
||||
{file = "pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189"},
|
||||
{file = "pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
hyperscan = ["hyperscan (>=0.7)"]
|
||||
optional = ["typing-extensions (>=4)"]
|
||||
re2 = ["google-re2 (>=1.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pexpect"
|
||||
version = "4.9.0"
|
||||
@@ -408,6 +612,42 @@ files = [
|
||||
[package.dependencies]
|
||||
wcwidth = "*"
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
version = "7.2.2"
|
||||
description = "Cross-platform lib for process and system monitoring."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["dev"]
|
||||
markers = "sys_platform != \"emscripten\" and sys_platform != \"cygwin\""
|
||||
files = [
|
||||
{file = "psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b"},
|
||||
{file = "psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1"},
|
||||
{file = "psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8"},
|
||||
{file = "psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc"},
|
||||
{file = "psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988"},
|
||||
{file = "psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee"},
|
||||
{file = "psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["abi3audit", "black", "check-manifest", "colorama ; os_name == \"nt\"", "coverage", "packaging", "psleak", "pylint", "pyperf", "pypinfo", "pyreadline3 ; os_name == \"nt\"", "pytest", "pytest-cov", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""]
|
||||
test = ["psleak", "pytest", "pytest-instafail", "pytest-xdist", "pywin32 ; os_name == \"nt\" and implementation_name != \"pypy\"", "setuptools", "wheel ; os_name == \"nt\" and implementation_name != \"pypy\"", "wmi ; os_name == \"nt\" and implementation_name != \"pypy\""]
|
||||
|
||||
[[package]]
|
||||
name = "ptyprocess"
|
||||
version = "0.7.0"
|
||||
@@ -523,18 +763,6 @@ files = [
|
||||
{file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2025.2"
|
||||
description = "Provider of IANA time zone data"
|
||||
optional = false
|
||||
python-versions = ">=2"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"},
|
||||
{file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.14"
|
||||
@@ -549,5 +777,5 @@ files = [
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "b03ef0369277d183d033049206a4cfd5f450473179995a4a79165fbb84d81fa0"
|
||||
python-versions = "^3.13"
|
||||
content-hash = "4bb5001f3c3cd2a3ab45ada4dc6c408703d1c309a499afde1845922ed792d59a"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "hotpocket-apple"
|
||||
version = "25.11.12"
|
||||
version = "26.8.22"
|
||||
description = "HotPocket Apple Integrations"
|
||||
authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
|
||||
license = "Apache-2.0"
|
||||
@@ -8,17 +8,16 @@ readme = "README.md"
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
python = "^3.13"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
factory-boy = "3.3.3"
|
||||
flake8 = "7.3.0"
|
||||
flake8-commas = "4.0.0"
|
||||
hotpocket-workspace-tools = {path = "../packages/workspace_tools", develop = true}
|
||||
ipdb = "0.13.13"
|
||||
ipython = "9.6.0"
|
||||
isort = "7.0.0"
|
||||
mypy = "1.18.2"
|
||||
ipython = "9.16.1"
|
||||
isort = "8.0.1"
|
||||
mypy = "2.3.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
|
||||
@@ -29,7 +29,7 @@ def flake8(ctx: Context):
|
||||
|
||||
|
||||
@task
|
||||
def isort(ctx, check=False, diff=False):
|
||||
def isort(ctx: Context, check=False, diff=False):
|
||||
command_parts = [
|
||||
'isort',
|
||||
]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
ARG APP_USER_UID=1000
|
||||
ARG APP_USER_GID=1000
|
||||
ARG IMAGE_ID=development.00000000
|
||||
ARG IMAGE_VERSION=v00.00.00
|
||||
ARG IMAGE_REVISION=00000000
|
||||
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:build-node-20251014-01 AS development
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:build-node-20260818-01 AS development
|
||||
|
||||
ARG APP_USER_UID
|
||||
ARG APP_USER_GID
|
||||
@@ -12,7 +14,7 @@ COPY --chown=$APP_USER_UID:$APP_USER_GID backend/ops/bin/*.sh /srv/bin/
|
||||
|
||||
VOLUME ["/srv/node_modules", "/srv/venv"]
|
||||
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:build-python-20251014-01 AS deployment-build
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:build-python-20260818-01 AS deployment-build
|
||||
|
||||
ARG APP_USER_UID
|
||||
ARG APP_USER_GID
|
||||
@@ -25,13 +27,13 @@ COPY --chown=$APP_USER_UID:$APP_USER_GID packages/common/ /srv/packages/common/
|
||||
COPY --chown=$APP_USER_UID:$APP_USER_GID packages/soa/ /srv/packages/soa/
|
||||
|
||||
RUN poetry install --only main,deployment && \
|
||||
minify -i --css-precision 0 --js-precision 0 --js-version 2022 hotpocket_backend/apps/ui/static/ui/css/hotpocket-backend*.css hotpocket_backend/apps/ui/static/ui/js/hotpocket*.js && \
|
||||
minify -i --css-precision 0 --js-precision 0 --js-version 2022 hotpocket_backend/apps/ui/static/ui/css/hotpocket-backend*.css hotpocket_backend/apps/ui/static/ui/js/hotpocket-backend*.js && \
|
||||
./manage.py collectstatic --settings hotpocket_backend.settings.deployment.build --noinput && \
|
||||
find hotpocket_backend/static/ -name "*.map*" -delete && \
|
||||
rm -f hotpocket_backend/settings/deployment/build.py && \
|
||||
rm -rf node_modules/
|
||||
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:base-20251014-01 AS deployment-base
|
||||
FROM docker-hosted.nexus.bthlabs.pl/hotpocket/base:base-20260818-01 AS deployment-base
|
||||
|
||||
ARG APP_USER_UID
|
||||
ARG APP_USER_GID
|
||||
@@ -63,6 +65,20 @@ CMD ["/srv/venv/bin/gunicorn", "-c", "/srv/lib/gunicorn.conf.py", "hotpocket_bac
|
||||
|
||||
FROM deployment-base AS deployment
|
||||
|
||||
ARG IMAGE_VERSION
|
||||
ARG IMAGE_REVISION
|
||||
|
||||
LABEL org.opencontainers.image.authors="Tomek Wójcik <contact@bthlabs.pl>"
|
||||
LABEL org.opencontainers.image.url="https://git.bthlabs.pl/tomekwojcik/hotpocket"
|
||||
LABEL org.opencontainers.image.documentation="https://git.bthlabs.pl/tomekwojcik/hotpocket"
|
||||
LABEL org.opencontainers.image.source="https://git.bthlabs.pl/tomekwojcik/hotpocket.git"
|
||||
LABEL org.opencontainers.image.version="${IMAGE_VERSION}"
|
||||
LABEL org.opencontainers.image.revision="${IMAGE_REVISION}"
|
||||
LABEL org.opencontainers.image.vendor="BTHLabs <contact@bthlabs.pl>"
|
||||
LABEL org.opencontainers.image.title="HotPocket by BTHLabs"
|
||||
LABEL org.opencontainers.image.description="Minimal self-hosted bookmarking app :)"
|
||||
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
||||
|
||||
ARG APP_USER_UID
|
||||
ARG APP_USER_GID
|
||||
ARG IMAGE_ID
|
||||
@@ -77,6 +93,20 @@ VOLUME ["/srv/run", "/srv/uploads"]
|
||||
|
||||
FROM deployment-base AS aio
|
||||
|
||||
ARG IMAGE_VERSION
|
||||
ARG IMAGE_REVISION
|
||||
|
||||
LABEL org.opencontainers.image.authors="Tomek Wójcik <contact@bthlabs.pl>"
|
||||
LABEL org.opencontainers.image.url="https://git.bthlabs.pl/tomekwojcik/hotpocket"
|
||||
LABEL org.opencontainers.image.documentation="https://git.bthlabs.pl/tomekwojcik/hotpocket"
|
||||
LABEL org.opencontainers.image.source="https://git.bthlabs.pl/tomekwojcik/hotpocket.git"
|
||||
LABEL org.opencontainers.image.version="${IMAGE_VERSION}"
|
||||
LABEL org.opencontainers.image.revision="${IMAGE_REVISION}"
|
||||
LABEL org.opencontainers.image.vendor="BTHLabs <contact@bthlabs.pl>"
|
||||
LABEL org.opencontainers.image.title="BTHLabs Docker Bastion"
|
||||
LABEL org.opencontainers.image.description="Minimal self-hosted bookmarking app :)"
|
||||
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
||||
|
||||
ARG APP_USER_UID
|
||||
ARG APP_USER_GID
|
||||
ARG IMAGE_ID
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
version = '25.11.12'
|
||||
version = '26.8.22'
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from .access_token import AccessToken # noqa: F401
|
||||
from .account import AccountAdmin # noqa: F401
|
||||
from .auth_key import AuthKey # noqa: F401
|
||||
|
||||
@@ -2,16 +2,41 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from hotpocket_backend.apps.accounts.models import AccessToken
|
||||
|
||||
|
||||
class AccessTokenAdmin(admin.ModelAdmin):
|
||||
list_display = ('pk', 'account_uuid', 'origin', 'created_at', 'is_active')
|
||||
list_display = (
|
||||
'pk', 'account_uuid', 'origin', 'created_at', 'render_is_active',
|
||||
)
|
||||
search_fields = ('pk', 'account_uuid', 'key', 'origin')
|
||||
readonly_fields = (
|
||||
'pk',
|
||||
'account_uuid',
|
||||
'key',
|
||||
'origin',
|
||||
'meta',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
)
|
||||
ordering = ['-created_at']
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return request.user.is_superuser
|
||||
|
||||
@admin.display(
|
||||
description=_('Is Active?'), boolean=True, ordering='-deleted_at',
|
||||
)
|
||||
def render_is_active(self, obj: AccessToken | None = None) -> bool | None:
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
return obj.is_active
|
||||
|
||||
|
||||
admin.site.register(AccessToken, AccessTokenAdmin)
|
||||
|
||||
@@ -3,15 +3,26 @@ from __future__ import annotations
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from hotpocket_backend.apps.accounts.models import Account
|
||||
|
||||
|
||||
class AccountAdmin(UserAdmin):
|
||||
list_display = (*UserAdmin.list_display, 'is_active')
|
||||
list_display = (*UserAdmin.list_display, 'render_is_active')
|
||||
ordering = ['username']
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return request.user.is_superuser
|
||||
|
||||
@admin.display(
|
||||
description=_('Is Active?'), boolean=True, ordering='-is_active',
|
||||
)
|
||||
def render_is_active(self, obj: Account | None = None) -> bool | None:
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
return obj.is_active
|
||||
|
||||
|
||||
admin.site.register(Account, AccountAdmin)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from hotpocket_backend.apps.accounts.models import AuthKey
|
||||
|
||||
|
||||
class AuthKeyAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'pk', 'account_uuid', 'key', 'created_at', 'consumed_at', 'render_is_active',
|
||||
)
|
||||
search_fields = ('pk', 'account_uuid', 'key')
|
||||
readonly_fields = (
|
||||
'pk',
|
||||
'account_uuid',
|
||||
'key',
|
||||
'consumed_at',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
)
|
||||
ordering = ['-created_at']
|
||||
|
||||
def has_change_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return request.user.is_superuser
|
||||
|
||||
@admin.display(
|
||||
description=_('Is Active?'), boolean=True, ordering='-deleted_at',
|
||||
)
|
||||
def render_is_active(self, obj: AuthKey | None = None) -> bool | None:
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
return obj.is_active
|
||||
|
||||
|
||||
admin.site.register(AuthKey, AuthKeyAdmin)
|
||||
@@ -79,3 +79,17 @@ class AuthKeysService:
|
||||
raise self.NotFound(
|
||||
f'Auth Key not found: key=`{key}`',
|
||||
) from exception
|
||||
|
||||
def clean_expired_auth_keys(self) -> int:
|
||||
current_timestamp = now()
|
||||
cutoff_timestamp = current_timestamp - datetime.timedelta(
|
||||
seconds=(settings.AUTH_KEY_TTL + 5),
|
||||
)
|
||||
|
||||
deleted, _ = AuthKey.active_objects.\
|
||||
filter(
|
||||
created_at__lte=cutoff_timestamp,
|
||||
).\
|
||||
delete()
|
||||
|
||||
return deleted
|
||||
|
||||
20
services/backend/hotpocket_backend/apps/accounts/tasks.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from celery import shared_task
|
||||
from django import db
|
||||
|
||||
from hotpocket_backend.apps.accounts.services import AuthKeysService
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@shared_task
|
||||
def clean_expired_auth_keys():
|
||||
with db.transaction.atomic():
|
||||
deleted_count = AuthKeysService().clean_expired_auth_keys()
|
||||
LOGGER.debug(
|
||||
'Deleted expired AuthKey objects: deleted_count=`%d`', deleted_count,
|
||||
)
|
||||
@@ -38,3 +38,5 @@ class PSettings(typing.Protocol):
|
||||
|
||||
UI_PAGE_HEAD_INCLUDES: list
|
||||
UI_PAGE_SCRIPT_INCLUDES: list
|
||||
|
||||
OPERATOR_EMAIL: str | None
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
from . import association # noqa: F401
|
||||
from . import save # noqa: F401
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from hotpocket_backend.apps.saves.models import Association
|
||||
|
||||
|
||||
class AssociationAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'pk', 'account_uuid', 'target', 'created_at', 'render_is_active',
|
||||
)
|
||||
search_fields = ('pk', 'account_uuid')
|
||||
fields = (
|
||||
'pk',
|
||||
'account_uuid',
|
||||
'archived_at',
|
||||
'starred_at',
|
||||
'target_meta',
|
||||
'target_title',
|
||||
'target_description',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
)
|
||||
readonly_fields = (
|
||||
'pk',
|
||||
'account_uuid',
|
||||
'target_meta',
|
||||
'target',
|
||||
'archived_at',
|
||||
'starred_at',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
)
|
||||
ordering = ['-created_at']
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return request.user.is_superuser
|
||||
|
||||
@admin.display(
|
||||
description=_('Is Active?'), boolean=True, ordering='-deleted_at',
|
||||
)
|
||||
def render_is_active(self, obj: Association | None = None) -> bool | None:
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
return obj.is_active
|
||||
|
||||
|
||||
admin.site.register(Association, AssociationAdmin)
|
||||
@@ -11,6 +11,26 @@ class SaveAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'pk', 'key', 'account_uuid', 'created_at', 'render_is_active',
|
||||
)
|
||||
search_fields = ('pk', 'account_uuid', 'url')
|
||||
fields = (
|
||||
'pk',
|
||||
'account_uuid',
|
||||
'key',
|
||||
'url',
|
||||
'title',
|
||||
'description',
|
||||
'last_processed_at',
|
||||
'is_netloc_banned',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
)
|
||||
readonly_fields = (
|
||||
'pk',
|
||||
'account_uuid',
|
||||
'key',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
)
|
||||
ordering = ['-created_at']
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 5.2.8 on 2025-11-18 14:13
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('saves', '0008_alter_save_url'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='save',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, db_index=True, default=None, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='save',
|
||||
name='title',
|
||||
field=models.CharField(blank=True, db_index=True, default=None, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='save',
|
||||
name='url',
|
||||
field=models.CharField(db_index=True, default=None, validators=[django.core.validators.URLValidator(schemes=['http', 'https'])]),
|
||||
),
|
||||
]
|
||||
@@ -20,7 +20,7 @@ class Save(Model):
|
||||
blank=False, null=False, default=None, db_index=True,
|
||||
)
|
||||
url = models.CharField(
|
||||
blank=False, null=False, default=None,
|
||||
blank=False, null=False, default=None, db_index=True,
|
||||
validators=[
|
||||
validators.URLValidator(schemes=['http', 'https']),
|
||||
],
|
||||
@@ -29,10 +29,10 @@ class Save(Model):
|
||||
blank=True, null=True, default=None, editable=False,
|
||||
)
|
||||
title = models.CharField(
|
||||
blank=True, null=True, default=None,
|
||||
blank=True, null=True, default=None, db_index=True,
|
||||
)
|
||||
description = models.CharField(
|
||||
blank=True, null=True, default=None,
|
||||
blank=True, null=True, default=None, db_index=True,
|
||||
)
|
||||
last_processed_at = models.DateTimeField(
|
||||
auto_now=False,
|
||||
|
||||
@@ -100,3 +100,9 @@ def page_includes(request: HttpRequest) -> dict:
|
||||
'script': settings.UI_PAGE_SCRIPT_INCLUDES,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def operator_email(request: HttpRequest) -> dict:
|
||||
return {
|
||||
'OPERATOR_EMAIL': settings.OPERATOR_EMAIL,
|
||||
}
|
||||
|
||||
21
services/backend/hotpocket_backend/apps/ui/dto/rpc.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
import pydantic
|
||||
|
||||
|
||||
class SavesCreateOut(pydantic.BaseModel):
|
||||
id: uuid.UUID
|
||||
target_uuid: uuid.UUID
|
||||
url: pydantic.AnyHttpUrl
|
||||
is_netloc_banned: bool
|
||||
|
||||
def to_rpc(self) -> dict:
|
||||
return {
|
||||
'id': self.id,
|
||||
'target_uuid': self.target_uuid,
|
||||
'url': str(self.url),
|
||||
'is_netloc_banned': self.is_netloc_banned,
|
||||
}
|
||||
@@ -151,7 +151,6 @@ class SettingsForm(Form):
|
||||
('cosmo', _('Cosmo')),
|
||||
('solar', _('Solar')),
|
||||
('sandstone', _('Sandstone')),
|
||||
('sketchy', _('Sketchy')),
|
||||
],
|
||||
)
|
||||
light_mode = forms.BooleanField(
|
||||
|
||||
@@ -3,19 +3,29 @@ from __future__ import annotations
|
||||
|
||||
from bthlabs_jsonrpc_core import register_method
|
||||
from django.http import HttpRequest
|
||||
from django.urls import reverse
|
||||
|
||||
from hotpocket_backend.apps.core.rpc import wrap_soa_errors
|
||||
from hotpocket_backend.apps.ui.dto.rpc import SavesCreateOut
|
||||
from hotpocket_backend.apps.ui.services.workflows import CreateSaveWorkflow
|
||||
from hotpocket_soa.dto.associations import AssociationOut
|
||||
|
||||
|
||||
@register_method(method='saves.create')
|
||||
@wrap_soa_errors
|
||||
def create(request: HttpRequest, url: str) -> AssociationOut:
|
||||
def create(request: HttpRequest, url: str) -> SavesCreateOut:
|
||||
association = CreateSaveWorkflow().run_rpc(
|
||||
request=request,
|
||||
account=request.user,
|
||||
url=url,
|
||||
)
|
||||
|
||||
return association
|
||||
result = SavesCreateOut.model_validate({
|
||||
'id': association.pk,
|
||||
'target_uuid': association.target_uuid,
|
||||
'url': request.build_absolute_uri(reverse(
|
||||
'ui.associations.view', args=(association.pk,),
|
||||
)),
|
||||
'is_netloc_banned': association.target.is_netloc_banned,
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
@@ -9,7 +9,10 @@ from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from hotpocket_backend.apps.accounts.types import PAccount
|
||||
from hotpocket_soa.dto.associations import AssociationOut
|
||||
from hotpocket_soa.dto.associations import (
|
||||
AssociationOut,
|
||||
AssociationWithTargetOut,
|
||||
)
|
||||
from hotpocket_soa.dto.celery import AsyncResultOut
|
||||
from hotpocket_soa.dto.saves import SaveIn, SaveOut
|
||||
|
||||
@@ -69,9 +72,14 @@ class CreateSaveWorkflow(SaveWorkflow):
|
||||
request: HttpRequest,
|
||||
account: PAccount,
|
||||
url: str,
|
||||
) -> AssociationOut:
|
||||
) -> AssociationWithTargetOut:
|
||||
save, association, processing_result = self.create_associate_and_process(
|
||||
account, url,
|
||||
)
|
||||
|
||||
return association
|
||||
result = AssociationWithTargetOut.from_association_save(
|
||||
association=association,
|
||||
save=save,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@@ -122,3 +122,11 @@ body.ui-mode-standalone #offcanvas-controls .offcanvas-body {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-login-logo {
|
||||
width: 128px;
|
||||
}
|
||||
|
||||
.ui-login-with-oidc-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 96 KiB |
@@ -45,7 +45,6 @@
|
||||
return null;
|
||||
}
|
||||
onLoad = (event) => {
|
||||
console.log('HotPocketApp.onLoad()', event);
|
||||
for (let pluginSpec of this.plugins) {
|
||||
if (pluginSpec[1].onLoad) {
|
||||
pluginSpec[1].onLoad(event);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% extends "ui/base.html" %}
|
||||
|
||||
{% load crispy_forms_tags i18n ui %}
|
||||
{% load crispy_forms_tags i18n static ui %}
|
||||
|
||||
{% block title %}{% translate 'Log in' %}{% endblock %}
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col col-12 col-md-6 offset-md-3">
|
||||
<img
|
||||
alt="HotPocket Icon"
|
||||
class="d-block ms-auto me-auto ui-login-logo"
|
||||
src="{% static 'ui/img/icon-mac-384.png' %}"
|
||||
>
|
||||
<div class="card">
|
||||
<div class="card-header text-center">
|
||||
<p class="fs-3 mb-0">{{ SITE_TITLE }}</p>
|
||||
@@ -24,12 +29,25 @@
|
||||
{% endif %}
|
||||
|
||||
{% if HOTPOCKET_OIDC_IS_ENABLED %}
|
||||
<a
|
||||
class="btn btn-primary d-block"
|
||||
href="{% url 'social:begin' 'hotpocket_oidc' %}"
|
||||
<form
|
||||
action="{% url 'social:begin' 'hotpocket_oidc' %}"
|
||||
class="d-block"
|
||||
method="post"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<button
|
||||
class="btn btn-primary d-block ui-login-with-oidc-button"
|
||||
type="submit"
|
||||
>
|
||||
{% blocktranslate %}Log in with {{ HOTPOCKET_OIDC_DISPLAY_NAME }}{% endblocktranslate %}
|
||||
</a>
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% if OPERATOR_EMAIL %}
|
||||
<p class="my-0 mt-2 text-center">
|
||||
<small>{% blocktranslate %}For support with your account, contact the <a href="mailto:{{ OPERATOR_EMAIL }}">instance operator</a>.{% endblocktranslate %}</small>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer d-flex align-items-center">
|
||||
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferer"><small>{{ association.target.url|render_url_domain }}</small></a>
|
||||
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferrer"><small>{{ association.target.url|render_url_domain }} <i class="bi bi-box-arrow-up-right"></i></small></a>
|
||||
<div class="ms-auto flex-shrink-0 d-flex align-items-center">
|
||||
{% if not association.archived_at %}
|
||||
<div class="spinner-border spinner-border-sm ui-htmx-indicator" role="status">
|
||||
|
||||
@@ -2,10 +2,24 @@
|
||||
|
||||
{% load i18n static ui %}
|
||||
|
||||
{% block title %}{{ association.title }}{% endblock %}
|
||||
{% block title %}{% if association.title %}{{ association.title }}{% else %}{{ association.target.url }}{% endif %}{% endblock %}
|
||||
|
||||
{% block button_bar_class %}d-none{% endblock %}
|
||||
|
||||
{% block page_head %}
|
||||
{{ block.super}}
|
||||
<meta property="og:title" content="{% if association.title %}{{ association.title }}{% else %}{{ association.target.url }}{% endif %}">
|
||||
{% if association.description %}
|
||||
<meta property="og:description" content="{{ association.description|truncatechars:125 }}">
|
||||
{% endif %}
|
||||
<meta property="og:image" content="{{ og_card_url }}">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:url" content="{{ share_url }}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="{{ SITE_TITLE }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block page_body %}
|
||||
<div id="ViewAssociationView" class="container pb-3">
|
||||
<p class="display-3 mt-3 mb-0 text-center">
|
||||
@@ -20,7 +34,7 @@
|
||||
{% blocktranslate with created_at=association.created_at %}Saved on {{ created_at }}{% endblocktranslate %}
|
||||
</span>
|
||||
<br>
|
||||
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferer">
|
||||
<a href="{{ association.target.url }}" target="_blank" rel="noopener noreferrer">
|
||||
{% translate 'View original' %} <i class="bi bi-box-arrow-up-right"></i>
|
||||
</a>
|
||||
</p>
|
||||
@@ -51,7 +65,7 @@
|
||||
<a
|
||||
class="btn btn-secondary btn-sm ui-noscript-show"
|
||||
href="{{ share_url }}"
|
||||
rel="noopener noreferer"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<i class="bi bi-link-45deg"></i> {% translate 'Share link' %}
|
||||
|
||||
@@ -130,6 +130,56 @@
|
||||
{% translate 'Log out' %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item px-3 d-flex justify-content-center">
|
||||
{% spaceless %}
|
||||
<a
|
||||
class="btn btn-outline-info btn-sm"
|
||||
href="https://apps.apple.com/pl/app/hotpocket-by-bthlabs/id6752321380"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
title="{% translate 'Safari and Share extension for iOS and macOS' %}"
|
||||
>
|
||||
<i class="bi bi-apple"></i>
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-outline-info btn-sm ms-1"
|
||||
href="https://chromewebstore.google.com/detail/save-to-hotpocket/mkmoejhhgnadmijpgkkioicjmikkkjbd"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
title="{% translate 'Chrome extension' %}"
|
||||
>
|
||||
<i class="bi bi-browser-chrome"></i>
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-outline-info btn-sm ms-1"
|
||||
href="https://addons.mozilla.org/en-GB/firefox/addon/save-to-hotpocket/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
title="{% translate 'Firefox extension' %}"
|
||||
>
|
||||
<i class="bi bi-browser-firefox"></i>
|
||||
</a>
|
||||
<a
|
||||
class="btn btn-outline-info btn-sm ms-1"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#modalPWA"
|
||||
href="#"
|
||||
title="{% translate 'Android PWA' %}"
|
||||
>
|
||||
<i class="bi bi-android2"></i>
|
||||
</a>
|
||||
<div class="vr my-1 ms-1 opacity-75"></div>
|
||||
<a
|
||||
class="btn btn-outline-info btn-sm ms-1"
|
||||
href="https://git.bthlabs.pl/tomekwojcik/hotpocket"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
title="{% translate 'Source code repository' %}"
|
||||
>
|
||||
<i class="bi bi-git"></i>
|
||||
</a>
|
||||
{% endspaceless %}
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'ui.accounts.login' %}">
|
||||
@@ -142,6 +192,38 @@
|
||||
{% include "ui/ui/partials/uname.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if not request.user.is_anonymous %}
|
||||
<div class="modal modal-fade" id="modalPWA" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="modalPWALabel">
|
||||
{% translate 'HotPocket on Android and others' %}
|
||||
</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class="mb-1">
|
||||
{% blocktranslate %}
|
||||
HotPocket doesn't natively support Android and other systems. However, it's a Progressive Web Application. You can install it from your browser and it'll register itself as share target.
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
<p class="mb-0">
|
||||
{% blocktranslate %}
|
||||
This is currently supported on Android and Windows 11 (when installed using Edge).
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">
|
||||
{% translate 'Cool' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
{% if save.is_youtube_video %}
|
||||
<div class="mb-0 d-flex justify-content-center">
|
||||
<iframe
|
||||
allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
allow="accelerometer *; clipboard-write *; encrypted-media *; gyroscope *; picture-in-picture *; web-share *;"
|
||||
allowfullscreen
|
||||
class="ui-youtube-iframe"
|
||||
frameborder="0"
|
||||
height="200"
|
||||
referrerpolicy="strict-origin"
|
||||
scrolling="no"
|
||||
src="{{ save|render_youtube_embed_url }}"
|
||||
title="YouTube video player"
|
||||
width="320"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<p class="mb-0 mt-2 text-center text-muted ui-uname">
|
||||
<span>
|
||||
<a href="https://hotpocket.app/" target="_blank" rel="noopener noreferer">{{ SITE_TITLE }}</a> v{{ VERSION }}
|
||||
<a href="https://hotpocket.app/" target="_blank" rel="noopener noreferrer">{{ SITE_TITLE }}</a> v{{ VERSION }}
|
||||
(<code>{{ IMAGE_ID }}</code>)
|
||||
</span>
|
||||
<br>
|
||||
|
||||
@@ -5,9 +5,11 @@ import logging
|
||||
import uuid
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
import django.db
|
||||
from django.http import HttpRequest, HttpResponse, JsonResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.templatetags.static import static
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import FormView, View
|
||||
@@ -25,7 +27,7 @@ from hotpocket_backend.apps.ui.forms.associations import (
|
||||
RefreshForm,
|
||||
)
|
||||
from hotpocket_backend.apps.ui.services import UIAssociationsService
|
||||
from hotpocket_common.constants import NULL_UUID, AssociationsSearchMode
|
||||
from hotpocket_common.constants import AssociationsSearchMode
|
||||
from hotpocket_soa.dto.associations import (
|
||||
AssociationOut,
|
||||
AssociationsQuery,
|
||||
@@ -175,7 +177,9 @@ def view(request: HttpRequest, pk: uuid.UUID) -> HttpResponse:
|
||||
if is_share is True:
|
||||
account_uuid = None
|
||||
else:
|
||||
account_uuid = NULL_UUID
|
||||
return redirect_to_login(
|
||||
reverse('ui.associations.view', args=(pk,)),
|
||||
)
|
||||
else:
|
||||
if is_share is False:
|
||||
account_uuid = request.user.pk
|
||||
@@ -198,12 +202,18 @@ def view(request: HttpRequest, pk: uuid.UUID) -> HttpResponse:
|
||||
if is_share is True:
|
||||
show_controls = show_controls and False
|
||||
|
||||
share_url = reverse(
|
||||
share_url = request.build_absolute_uri(
|
||||
reverse(
|
||||
'ui.associations.view',
|
||||
args=(association.pk,),
|
||||
query=[
|
||||
('share', 'true'),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
og_card_url = request.build_absolute_uri(
|
||||
static('ui/img/og-card.png'),
|
||||
)
|
||||
|
||||
return render(
|
||||
@@ -213,6 +223,12 @@ def view(request: HttpRequest, pk: uuid.UUID) -> HttpResponse:
|
||||
'association': association,
|
||||
'show_controls': show_controls,
|
||||
'share_url': share_url,
|
||||
'is_share': is_share,
|
||||
'og_card_url': (
|
||||
og_card_url
|
||||
if is_share is True
|
||||
else None
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -27,9 +27,6 @@ def page_not_found(request: HttpRequest,
|
||||
exception: Exception,
|
||||
template_name: str = ERROR_404_TEMPLATE_NAME,
|
||||
) -> HttpResponseNotFound:
|
||||
if exception:
|
||||
LOGGER.error('Exception: %s', exception, exc_info=exception)
|
||||
|
||||
return HttpResponseNotFound(render_to_string(
|
||||
'ui/errors/page_not_found.html',
|
||||
context={},
|
||||
|
||||
@@ -72,6 +72,7 @@ TEMPLATES = [
|
||||
'hotpocket_backend.apps.ui.context_processors.debug',
|
||||
'hotpocket_backend.apps.ui.context_processors.version',
|
||||
'hotpocket_backend.apps.ui.context_processors.appearance_settings',
|
||||
'hotpocket_backend.apps.ui.context_processors.operator_email',
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -295,3 +296,5 @@ SAVES_ASSOCIATION_ADAPTER = os.environ.get(
|
||||
UPLOADS_PATH = None
|
||||
|
||||
SITE_SHORT_TITLE = 'HotPocket'
|
||||
|
||||
OPERATOR_EMAIL = os.environ.get('HOTPOCKET_BACKEND_OPERATOR_EMAIL', None)
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from celery.schedules import crontab
|
||||
from corsheaders.defaults import default_headers
|
||||
|
||||
from .base import * # noqa: F401,F403
|
||||
@@ -46,6 +47,13 @@ SESSION_COOKIE_SECURE = True
|
||||
CRISPY_ALLOWED_TEMPLATE_PACKS = 'bootstrap5'
|
||||
CRISPY_TEMPLATE_PACK = 'bootstrap5'
|
||||
|
||||
CELERY_BEAT_SCHEDULE = {
|
||||
'clean-expired-auth-keys': {
|
||||
'task': 'hotpocket_backend.apps.accounts.tasks.clean_expired_auth_keys',
|
||||
'schedule': crontab(minute='30', hour='3'),
|
||||
},
|
||||
}
|
||||
|
||||
HOTPOCKET_BOT_STRATEGY = 'hotpocket_backend.apps.bot.strategy.basic:BasicStrategy'
|
||||
HOTPOCKET_BOT_BANNED_HOSTNAMES = [
|
||||
# YT returns dummy data when I try to fetch the page and extract
|
||||
|
||||
@@ -13,7 +13,7 @@ cat <<EOF
|
||||
|_|
|
||||
production
|
||||
|
||||
HotPocket v25.11.12 [${HOTPOCKET_BACKEND_IMAGE_ID}] (https://hotpocket.app/)
|
||||
HotPocket v26.8.22 [${HOTPOCKET_BACKEND_IMAGE_ID}] (https://hotpocket.app/)
|
||||
Copyright 2025-present by BTHLabs. All rights reserved. (https://bthlabs.pl/)
|
||||
Licensed under Apache-2.0
|
||||
EOF
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hotpocket-backend",
|
||||
"version": "25.11.12",
|
||||
"version": "26.8.22",
|
||||
"description": "HotPocket Backend",
|
||||
"main": "hotpocket_backend/apps/frontend/src/index.js",
|
||||
"repository": "https://git.bthlabs.pl/tomekwojcik/hotpocket",
|
||||
@@ -12,8 +12,8 @@
|
||||
"eslint": "npx eslint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.33.0",
|
||||
"eslint": "9.33.0",
|
||||
"globals": "14.0.0"
|
||||
"@eslint/js": "10.0.1",
|
||||
"eslint": "10.8.1",
|
||||
"globals": "17.11.0"
|
||||
}
|
||||
}
|
||||
|
||||