Refactor database layer: convert to DatabaseProvider class with initialization
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
build/
|
||||
.dart_tool/
|
||||
.git/
|
||||
.github/
|
||||
.gitignore
|
||||
.idea/
|
||||
.packages
|
||||
@@ -0,0 +1,9 @@
|
||||
# Environment variables for sky_kfm_backend
|
||||
# JWT secret used for signing tokens
|
||||
JWT_SECRET=your-super-secret-key-change-me
|
||||
# Secret pepper added to passwords before hashing (should be random and kept secret)
|
||||
PASSWORD_PEPPER=your-random-pepper-string-change-me
|
||||
# Database connection URL
|
||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/family_safety
|
||||
# TOKEN_LIFETIME in minutes
|
||||
TOKEN_LIFETIME=600
|
||||
@@ -0,0 +1,3 @@
|
||||
# https://dart.dev/guides/libraries/private-files
|
||||
# Created by `dart pub`
|
||||
.dart_tool/
|
||||
Generated
+3
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyInterpreterInspection" enabled="true" level="INFORMATION" enabled_by_default="true" />
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N802" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
Generated
+524
@@ -0,0 +1,524 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Dart Packages" type="DartPackagesLibraryType">
|
||||
<properties>
|
||||
<option name="packageNameToDirsMap">
|
||||
<entry key="_fe_analyzer_shared">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/_fe_analyzer_shared-99.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="adaptive_number">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/adaptive_number-1.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="analyzer">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/analyzer-12.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="args">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/args-2.7.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="async">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/async-2.13.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="bcrypt">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/bcrypt-1.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="boolean_selector">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/boolean_selector-2.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="buffer">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/buffer-1.2.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="charcode">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/charcode-1.4.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="cli_config">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/cli_config-0.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="clock">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/clock-1.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="collection">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/collection-1.19.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="convert">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/convert-3.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="coverage">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/coverage-1.15.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="crypto">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/crypto-3.0.7/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="dart_jsonwebtoken">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dart_jsonwebtoken-2.17.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="dotenv">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dotenv-4.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="ed25519_edwards">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/ed25519_edwards-0.3.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="file">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/file-7.0.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="fixnum">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/fixnum-1.1.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="frontend_server_client">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/frontend_server_client-4.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="glob">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/glob-2.1.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="http">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http-1.6.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="http_methods">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_methods-1.1.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="http_multi_server">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_multi_server-3.2.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="http_parser">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_parser-4.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="io">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/io-1.0.5/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="js">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/js-0.7.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="lints">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/lints-6.1.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="logging">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/logging-1.3.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="matcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/matcher-0.12.20/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="meta">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/meta-1.18.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="mime">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/mime-2.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="node_preamble">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/node_preamble-2.0.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="package_config">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/package_config-2.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="path">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/path-1.9.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="pointycastle">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pointycastle-3.9.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="pool">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pool-1.5.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="postgres">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/postgres-3.5.10/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="pub_semver">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pub_semver-2.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf-1.4.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf_packages_handler">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_packages_handler-3.0.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf_router">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_router-1.1.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf_static">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_static-1.1.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="shelf_web_socket">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_web_socket-3.0.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_map_stack_trace">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_map_stack_trace-2.1.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_maps">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_maps-0.10.13/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="source_span">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_span-1.10.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stack_trace">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/stack_trace-1.12.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="stream_channel">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/stream_channel-2.1.4/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="string_scanner">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/string_scanner-1.4.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="term_glyph">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/term_glyph-1.2.2/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/test-1.31.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test_api">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/test_api-0.7.12/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="test_core">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/test_core-0.6.18/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="typed_data">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/typed_data-1.4.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="uuid">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/uuid-4.5.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="vm_service">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/vm_service-15.2.0/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="watcher">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/watcher-1.2.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="web">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web-1.1.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="web_socket">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web_socket-1.0.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="web_socket_channel">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web_socket_channel-3.0.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="webkit_inspection_protocol">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/webkit_inspection_protocol-1.2.1/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="yaml">
|
||||
<value>
|
||||
<list>
|
||||
<option value="$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/yaml-3.1.3/lib" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</option>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/_fe_analyzer_shared-99.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/adaptive_number-1.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/analyzer-12.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/args-2.7.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/async-2.13.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/bcrypt-1.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/boolean_selector-2.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/buffer-1.2.3/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/charcode-1.4.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/cli_config-0.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/clock-1.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/collection-1.19.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/convert-3.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/coverage-1.15.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/crypto-3.0.7/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dart_jsonwebtoken-2.17.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/dotenv-4.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/ed25519_edwards-0.3.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/file-7.0.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/fixnum-1.1.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/frontend_server_client-4.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/glob-2.1.3/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http-1.6.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_methods-1.1.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_multi_server-3.2.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/http_parser-4.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/io-1.0.5/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/js-0.7.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/lints-6.1.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/logging-1.3.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/matcher-0.12.20/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/meta-1.18.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/mime-2.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/node_preamble-2.0.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/package_config-2.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/path-1.9.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pointycastle-3.9.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pool-1.5.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/postgres-3.5.10/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/pub_semver-2.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf-1.4.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_packages_handler-3.0.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_router-1.1.4/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_static-1.1.3/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/shelf_web_socket-3.0.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_map_stack_trace-2.1.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_maps-0.10.13/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/source_span-1.10.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/stack_trace-1.12.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/stream_channel-2.1.4/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/string_scanner-1.4.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/term_glyph-1.2.2/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/test-1.31.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/test_api-0.7.12/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/test_core-0.6.18/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/typed_data-1.4.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/uuid-4.5.3/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/vm_service-15.2.0/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/watcher-1.2.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web-1.1.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web_socket-1.0.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/web_socket_channel-3.0.3/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/webkit_inspection_protocol-1.2.1/lib" />
|
||||
<root url="file://$USER_HOME$/AppData/Local/Pub/Cache/hosted/pub.dev/yaml-3.1.3/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+31
@@ -0,0 +1,31 @@
|
||||
<component name="libraryTable">
|
||||
<library name="Dart SDK">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/_internal" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/async" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/cli" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/collection" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/concurrent" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/convert" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/core" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/developer" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/ffi" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/html" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/indexed_db" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/io" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/isolate" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/js" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/js_interop" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/js_interop_unsafe" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/js_util" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/math" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/mirrors" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/svg" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/typed_data" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/web_audio" />
|
||||
<root url="file://$PROJECT_DIR$/../../../../tools/flutter/bin/cache/dart-sdk/lib/web_gl" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/family_safety_tracker.iml" filepath="$PROJECT_DIR$/family_safety_tracker.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,62 @@
|
||||
# AGENTS.md - Family Safety Tracker
|
||||
|
||||
## Overview
|
||||
Dart server app (Shelf + PostgreSQL) for sharing geolocation with family members. REST API with JWT auth, bcrypt password hashing, and auto-expiring position data.
|
||||
|
||||
## Quick Start
|
||||
```bash
|
||||
dart pub get
|
||||
dart run bin/server.dart
|
||||
```
|
||||
Server starts on port `8080` (override with `PORT` env var).
|
||||
|
||||
## Code Structure
|
||||
- **`bin/`** - All application code lives here (not `lib/`, which is empty).
|
||||
- `bin/server.dart` - Entry point. Starts Shelf server, database connection, and cleanup timer.
|
||||
- `bin/routes/` - Route handlers (`auth_routes.dart`, `user_routes.dart`, `geo_routes.dart`)
|
||||
- `bin/repositories/` - Data access layer (`user_repo.dart`, `geoposition_repo.dart`)
|
||||
- `bin/models/` - Domain models (`user.dart`, `geoposition.dart`, `log.dart`)
|
||||
- `bin/database/` - Database connection and auto-migration
|
||||
- **`lib/`** - Empty scaffold directory (stale, can be ignored).
|
||||
|
||||
## Database
|
||||
- PostgreSQL with connection via environment variables (`POSTGRES_HOST`, `POSTGRES_DB`, etc.) or defaults.
|
||||
- **Auto-migration**: Tables are created on startup via `Database.initialize()`. No manual migration needed.
|
||||
- Tables: `users`, `geopositions`, `logs`.
|
||||
|
||||
## Runtime Behavior
|
||||
- Expired geopositions are cleaned up every 5 minutes by a periodic timer in `server.dart`.
|
||||
- Share links use UUIDs stored in-memory via `GeopositionRepository`.
|
||||
|
||||
## API Endpoints
|
||||
- `POST /login` - Authenticate with login/password, returns user data.
|
||||
- `/user` - CRUD for users.
|
||||
- `/geo` - POST to create position, UPDATE to update (with lifetime expiry).
|
||||
- `GET /watch?unique_id=...` - Returns latest position for a share link.
|
||||
- `/share` - Creates a one-time share link UUID.
|
||||
|
||||
## Testing
|
||||
```bash
|
||||
dart test
|
||||
```
|
||||
Tests spawn the server process and hit endpoints. Server listens on port `8080` by default.
|
||||
|
||||
## Build/Quality Commands
|
||||
```bash
|
||||
dart analyze # Static analysis (uses analysis_options.yaml)
|
||||
dart format --set . # Format code
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
- `shelf`, `shelf_router` - HTTP framework
|
||||
- `postgres` - PostgreSQL driver
|
||||
- `bcrypt` - Password hashing
|
||||
- `dart_jsonwebtoken` - JWT tokens
|
||||
- `dotenv` - Environment config
|
||||
- `uuid` - UUID generation
|
||||
|
||||
## Notes
|
||||
- SDK: `^3.10.1`
|
||||
- No Docker setup present (`.dockerignore` exists but no `Dockerfile`).
|
||||
- Documentation in `README.md` is in Russian; the API is designed for geolocation sharing between family members.
|
||||
- `test_bcrypt.dart` is a standalone test file, not part of the test suite.
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.0.0
|
||||
|
||||
- Initial version.
|
||||
@@ -0,0 +1,18 @@
|
||||
A server app built using [Shelf](https://pub.dev/packages/shelf),
|
||||
|
||||
Это новый проект.
|
||||
Давай добавим описание проекта -
|
||||
Сервер - приложения для реализации возможности делиться геопозицией с другим человеком.
|
||||
База данных (в данном случае это будет postges) с отметками о геопозиции человека
|
||||
Какие таблицы будут в базе данных -
|
||||
Пользователи - ID, login, pwd
|
||||
Geoposition - id, x value, y value, datetime, lifetime
|
||||
Logs - username, action, datetime
|
||||
|
||||
Основа приложения - это REST API.
|
||||
Вот какие методы нужны.
|
||||
/login - авторизация.
|
||||
/user - CRUD пользователей.
|
||||
/geo - POST - создание позиции, UPDATE - обновление позиции. (при создании указывается время жизни, после которого данные будут удалены из базы)
|
||||
/watch?{unique id} - возращает геопозицию+время последней отметки + оставшееся время жизни отметки
|
||||
/share - метод который создает одноразовую ссылку (/watch?{unique id} ) - по которой доступны данные о геопозиции. В памяти приложения создается связь между geo из таблицы и {unique id}
|
||||
@@ -0,0 +1,30 @@
|
||||
# This file configures the static analysis results for your project (errors,
|
||||
# warnings, and lints).
|
||||
#
|
||||
# This enables the 'recommended' set of lints from `package:lints`.
|
||||
# This set helps identify many issues that may lead to problems when running
|
||||
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||
# style and format.
|
||||
#
|
||||
# If you want a smaller set of lints you can change this to specify
|
||||
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||
# (the recommended set includes the core lints).
|
||||
# The core lints are also what is used by pub.dev for scoring packages.
|
||||
|
||||
include: package:lints/recommended.yaml
|
||||
|
||||
# Uncomment the following section to specify additional rules.
|
||||
|
||||
# linter:
|
||||
# rules:
|
||||
# - camel_case_types
|
||||
|
||||
# analyzer:
|
||||
# exclude:
|
||||
# - path/to/excluded/files/**
|
||||
|
||||
# For more information about the core and recommended set of lints, see
|
||||
# https://dart.dev/go/core-lints
|
||||
|
||||
# For additional information about configuring this file, see
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
@@ -0,0 +1,356 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bcrypt/bcrypt.dart';
|
||||
import 'package:dotenv/dotenv.dart';
|
||||
import 'package:postgres/postgres.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../models/user.dart';
|
||||
import '../models/geoposition.dart';
|
||||
import '../models/log.dart';
|
||||
|
||||
class DatabaseProvider {
|
||||
late Connection _dbConnection;
|
||||
|
||||
final Map<String, int> _shareLinks = {};
|
||||
final _uuid = const Uuid();
|
||||
|
||||
Future<void> initialize() async {
|
||||
final dotenv = DotEnv();
|
||||
|
||||
final host = dotenv['POSTGRES_HOST'] ?? 'localhost';
|
||||
final port = int.parse(dotenv['POSTGRES_PORT'] ?? '5432');
|
||||
final databaseName = dotenv['POSTGRES_DB'] ?? 'family_safety';
|
||||
final username = dotenv['POSTGRES_USER'] ?? 'postgres';
|
||||
final password = dotenv['POSTGRES_PASSWORD'] ?? '';
|
||||
|
||||
try {
|
||||
final defaultConnection = await Connection.open(
|
||||
settings: ConnectionSettings(sslMode: SslMode.disable),
|
||||
Endpoint(
|
||||
host: host,
|
||||
port: port,
|
||||
database: 'postgres',
|
||||
username: username,
|
||||
password: password,
|
||||
),
|
||||
);
|
||||
|
||||
final results = await defaultConnection.execute(
|
||||
Sql.named('SELECT 1 FROM pg_database WHERE datname = @dbName'),
|
||||
parameters: {'dbName': databaseName},
|
||||
);
|
||||
|
||||
if (results.isEmpty) {
|
||||
await defaultConnection.execute(
|
||||
Sql.named('CREATE DATABASE @dbName'),
|
||||
parameters: {'dbName': databaseName},
|
||||
);
|
||||
print('Database $databaseName created.');
|
||||
} else {
|
||||
print('Database $databaseName already exists.');
|
||||
}
|
||||
|
||||
await defaultConnection.close();
|
||||
|
||||
_dbConnection = await Connection.open(
|
||||
settings: ConnectionSettings(sslMode: SslMode.disable),
|
||||
Endpoint(
|
||||
host: host,
|
||||
port: port,
|
||||
database: databaseName,
|
||||
username: username,
|
||||
password: password,
|
||||
),
|
||||
);
|
||||
print('Connected to database $databaseName.');
|
||||
|
||||
await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
login VARCHAR(255) UNIQUE NOT NULL,
|
||||
pwd_hash VARCHAR(255) NOT NULL
|
||||
)
|
||||
'''),
|
||||
);
|
||||
|
||||
await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
CREATE TABLE IF NOT EXISTS geopositions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
x_value DOUBLE PRECISION NOT NULL,
|
||||
y_value DOUBLE PRECISION NOT NULL,
|
||||
datetime TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
lifetime INTERVAL NOT NULL,
|
||||
expires_at TIMESTAMP NOT NULL
|
||||
)
|
||||
'''),
|
||||
);
|
||||
|
||||
await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
CREATE TABLE IF NOT EXISTS logs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(255) NOT NULL,
|
||||
action VARCHAR(255) NOT NULL,
|
||||
datetime TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
)
|
||||
'''),
|
||||
);
|
||||
|
||||
print('All tables ensured to exist.');
|
||||
} catch (e, stackTrace) {
|
||||
stderr.writeln('Database initialization error: $e');
|
||||
stderr.writeln(stackTrace);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
await _dbConnection.close();
|
||||
}
|
||||
|
||||
// ==================== User operations ====================
|
||||
|
||||
Future<User?> findUserByLogin(String login) async {
|
||||
final results = await _dbConnection.execute(
|
||||
Sql.named('SELECT id, login, pwd_hash FROM users WHERE login = @login'),
|
||||
parameters: {'login': login},
|
||||
);
|
||||
|
||||
if (results.isEmpty) return null;
|
||||
final row = results.first;
|
||||
return User(
|
||||
id: int.parse(row[0].toString()),
|
||||
login: row[1] as String,
|
||||
pwdHash: row[2] as String,
|
||||
);
|
||||
}
|
||||
|
||||
Future<User> createUser(String login, String password) async {
|
||||
final hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt());
|
||||
|
||||
final results = await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
INSERT INTO users (login, pwd_hash) VALUES (@login, @pwdHash)
|
||||
RETURNING id, login, pwd_hash
|
||||
'''),
|
||||
parameters: {
|
||||
'login': login,
|
||||
'pwdHash': hashedPassword,
|
||||
},
|
||||
);
|
||||
|
||||
final row = results.first;
|
||||
return User(
|
||||
id: int.parse(row[0].toString()),
|
||||
login: row[1] as String,
|
||||
pwdHash: row[2] as String,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> deleteUser(int id) async {
|
||||
await _dbConnection.execute(
|
||||
Sql.named('DELETE FROM users WHERE id = @id'),
|
||||
parameters: {'id': id},
|
||||
);
|
||||
}
|
||||
|
||||
Future<User> updateUser(int id, String newLogin, String? newPassword) async {
|
||||
if (newPassword != null) {
|
||||
final hashedPassword = BCrypt.hashpw(newPassword, BCrypt.gensalt());
|
||||
await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
UPDATE users SET login = @login, pwd_hash = @pwdHash WHERE id = @id
|
||||
'''),
|
||||
parameters: {
|
||||
'login': newLogin,
|
||||
'pwdHash': hashedPassword,
|
||||
'id': id,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _dbConnection.execute(
|
||||
Sql.named('UPDATE users SET login = @login WHERE id = @id'),
|
||||
parameters: {
|
||||
'login': newLogin,
|
||||
'id': id,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final user = await findUserByLogin(newLogin);
|
||||
return user!;
|
||||
}
|
||||
|
||||
Future<List<User>> getAllUsers() async {
|
||||
final results = await _dbConnection.execute(
|
||||
Sql.named('SELECT id, login, pwd_hash FROM users'),
|
||||
);
|
||||
|
||||
return results
|
||||
.map(
|
||||
(row) => User(
|
||||
id: int.parse(row[0].toString()),
|
||||
login: row[1] as String,
|
||||
pwdHash: row[2] as String,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// ==================== Geoposition operations ====================
|
||||
|
||||
Future<Geoposition> createPosition(
|
||||
int userId,
|
||||
double x,
|
||||
double y,
|
||||
Duration lifetime,
|
||||
) async {
|
||||
final expiresAt = DateTime.now().add(lifetime);
|
||||
|
||||
final results = await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
INSERT INTO geopositions (user_id, x_value, y_value, datetime, lifetime, expires_at)
|
||||
VALUES (@userId, @xValue, @yValue, NOW(), @lifetime, @expiresAt)
|
||||
RETURNING id, user_id, x_value, y_value, datetime, lifetime, expires_at
|
||||
'''),
|
||||
parameters: {
|
||||
'userId': userId,
|
||||
'xValue': x,
|
||||
'yValue': y,
|
||||
'lifetime': _toInterval(lifetime),
|
||||
'expiresAt': expiresAt.toIso8601String(),
|
||||
},
|
||||
);
|
||||
|
||||
final row = results.first;
|
||||
return Geoposition(
|
||||
id: int.parse(row[0].toString()),
|
||||
userId: int.parse(row[1].toString()),
|
||||
xValue: double.parse(row[2].toString()),
|
||||
yValue: double.parse(row[3].toString()),
|
||||
datetime: DateTime.parse(row[4].toString()),
|
||||
lifetime: lifetime,
|
||||
expiresAt: DateTime.parse(row[6].toString()),
|
||||
);
|
||||
}
|
||||
|
||||
Future<Geoposition> updatePosition(
|
||||
int userId,
|
||||
double x,
|
||||
double y,
|
||||
Duration lifetime,
|
||||
) async {
|
||||
final expiresAt = DateTime.now().add(lifetime);
|
||||
|
||||
final results = await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
INSERT INTO geopositions (user_id, x_value, y_value, datetime, lifetime, expires_at)
|
||||
VALUES (@userId, @xValue, @yValue, NOW(), @lifetime, @expiresAt)
|
||||
RETURNING id, user_id, x_value, y_value, datetime, lifetime, expires_at
|
||||
'''),
|
||||
parameters: {
|
||||
'userId': userId,
|
||||
'xValue': x,
|
||||
'yValue': y,
|
||||
'lifetime': _toInterval(lifetime),
|
||||
'expiresAt': expiresAt.toIso8601String(),
|
||||
},
|
||||
);
|
||||
|
||||
final row = results.first;
|
||||
return Geoposition(
|
||||
id: int.parse(row[0].toString()),
|
||||
userId: int.parse(row[1].toString()),
|
||||
xValue: double.parse(row[2].toString()),
|
||||
yValue: double.parse(row[3].toString()),
|
||||
datetime: DateTime.parse(row[4].toString()),
|
||||
lifetime: lifetime,
|
||||
expiresAt: DateTime.parse(row[6].toString()),
|
||||
);
|
||||
}
|
||||
|
||||
Future<Geoposition?> getLatestPosition(int userId) async {
|
||||
final results = await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
SELECT id, user_id, x_value, y_value, datetime, lifetime, expires_at
|
||||
FROM geopositions
|
||||
WHERE user_id = @userId AND expires_at > NOW()
|
||||
ORDER BY datetime DESC
|
||||
LIMIT 1
|
||||
'''),
|
||||
parameters: {'userId': userId},
|
||||
);
|
||||
|
||||
if (results.isEmpty) return null;
|
||||
|
||||
final row = results.first;
|
||||
return Geoposition(
|
||||
id: int.parse(row[0].toString()),
|
||||
userId: int.parse(row[1].toString()),
|
||||
xValue: double.parse(row[2].toString()),
|
||||
yValue: double.parse(row[3].toString()),
|
||||
datetime: DateTime.parse(row[4].toString()),
|
||||
lifetime: Duration(
|
||||
seconds: int.tryParse(row[5].toString()) ?? 0),
|
||||
expiresAt: DateTime.parse(row[6].toString()),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> cleanupExpired() async {
|
||||
await _dbConnection.execute(
|
||||
Sql.named('DELETE FROM geopositions WHERE expires_at < NOW()'),
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== Share operations ====================
|
||||
|
||||
String createShareId(int userId) {
|
||||
final uniqueId = _uuid.v4();
|
||||
_shareLinks[uniqueId] = userId;
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
int? getUserIdByShareId(String uniqueId) {
|
||||
return _shareLinks[uniqueId];
|
||||
}
|
||||
|
||||
// ==================== Log operations ====================
|
||||
|
||||
Future<void> createLog(String username, String action) async {
|
||||
await _dbConnection.execute(
|
||||
Sql.named('''
|
||||
INSERT INTO logs (username, action) VALUES (@username, @action)
|
||||
'''),
|
||||
parameters: {
|
||||
'username': username,
|
||||
'action': action,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Log>> getAllLogs() async {
|
||||
final results = await _dbConnection.execute(
|
||||
Sql.named('SELECT id, username, action, datetime FROM logs'),
|
||||
);
|
||||
|
||||
return results
|
||||
.map(
|
||||
(row) => Log(
|
||||
id: int.parse(row[0].toString()),
|
||||
username: row[1] as String,
|
||||
action: row[2] as String,
|
||||
datetime: DateTime.parse(row[3].toString()),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
String _toInterval(Duration duration) {
|
||||
final seconds = duration.inSeconds;
|
||||
return '$seconds seconds';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
login VARCHAR(255) UNIQUE NOT NULL,
|
||||
pwd_hash VARCHAR(255) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS geopositions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id),
|
||||
x_value DOUBLE PRECISION NOT NULL,
|
||||
y_value DOUBLE PRECISION NOT NULL,
|
||||
datetime TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
lifetime INTERVAL NOT NULL,
|
||||
expires_at TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS logs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(255) NOT NULL,
|
||||
action VARCHAR(255) NOT NULL,
|
||||
datetime TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
@@ -0,0 +1,41 @@
|
||||
class Geoposition {
|
||||
final int id;
|
||||
final int userId;
|
||||
final double xValue;
|
||||
final double yValue;
|
||||
final DateTime datetime;
|
||||
final Duration lifetime;
|
||||
final DateTime expiresAt;
|
||||
|
||||
Geoposition({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.xValue,
|
||||
required this.yValue,
|
||||
required this.datetime,
|
||||
required this.lifetime,
|
||||
required this.expiresAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'x': xValue,
|
||||
'y': yValue,
|
||||
'datetime': datetime.toIso8601String(),
|
||||
'remainingSeconds': expiresAt.difference(DateTime.now()).inSeconds,
|
||||
};
|
||||
}
|
||||
|
||||
factory Geoposition.fromMap(Map<String, dynamic> map) {
|
||||
return Geoposition(
|
||||
id: map['id'],
|
||||
userId: map['user_id'],
|
||||
xValue: map['x_value'].toDouble(),
|
||||
yValue: map['y_value'].toDouble(),
|
||||
datetime: map['datetime'] as DateTime,
|
||||
lifetime: Duration(seconds: map['lifetime']),
|
||||
expiresAt: map['expires_at'] as DateTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
class Log {
|
||||
final int id;
|
||||
final String username;
|
||||
final String action;
|
||||
final DateTime datetime;
|
||||
|
||||
Log({
|
||||
required this.id,
|
||||
required this.username,
|
||||
required this.action,
|
||||
required this.datetime,
|
||||
});
|
||||
|
||||
factory Log.fromMap(Map<String, dynamic> map) {
|
||||
return Log(
|
||||
id: map['id'],
|
||||
username: map['username'],
|
||||
action: map['action'],
|
||||
datetime: map['datetime'] as DateTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
class User {
|
||||
final int id;
|
||||
final String login;
|
||||
final String pwdHash;
|
||||
|
||||
User({
|
||||
required this.id,
|
||||
required this.login,
|
||||
required this.pwdHash,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'login': login,
|
||||
};
|
||||
}
|
||||
|
||||
factory User.fromMap(Map<String, dynamic> map) {
|
||||
return User(
|
||||
id: map['id'],
|
||||
login: map['login'],
|
||||
pwdHash: map['pwd_hash'],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf_router/shelf_router.dart';
|
||||
import 'package:bcrypt/bcrypt.dart';
|
||||
import '../database/database_provider.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class AuthRoutes {
|
||||
final DatabaseProvider database;
|
||||
|
||||
AuthRoutes(this.database);
|
||||
|
||||
Router get routes {
|
||||
final router = Router();
|
||||
router.post('/login', _login);
|
||||
router.get('/watch', _watch);
|
||||
return router;
|
||||
}
|
||||
|
||||
Future<Response> _login(Request request) async {
|
||||
final body = await request.readAsString();
|
||||
final data = jsonDecode(body);
|
||||
|
||||
final login = data['login'];
|
||||
final password = data['password'];
|
||||
|
||||
final user = await database.findUserByLogin(login);
|
||||
|
||||
if (user == null || !BCrypt.checkpw(password, user.pwdHash)) {
|
||||
return Response(401, body: 'Invalid credentials');
|
||||
}
|
||||
|
||||
return Response(200, body: jsonEncode({'user': user.toMap()}));
|
||||
}
|
||||
|
||||
Future<Response> _watch(Request request) async {
|
||||
final uniqueId = request.url.queryParameters['unique_id'];
|
||||
|
||||
final userId = database.getUserIdByShareId(uniqueId!);
|
||||
|
||||
if (userId == null) {
|
||||
return Response(404, body: 'Share link not found');
|
||||
}
|
||||
|
||||
final position = await database.getLatestPosition(userId);
|
||||
|
||||
if (position == null) {
|
||||
return Response(404, body: 'No position available');
|
||||
}
|
||||
|
||||
return Response(200, body: position.toJson());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf_router/shelf_router.dart';
|
||||
import '../database/database_provider.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class GeoRoutes {
|
||||
final DatabaseProvider database;
|
||||
|
||||
GeoRoutes(this.database);
|
||||
|
||||
Router get routes {
|
||||
final router = Router();
|
||||
router.post('/geo', _createPosition);
|
||||
router.put('/geo', _updatePosition);
|
||||
router.post('/share', _createShare);
|
||||
return router;
|
||||
}
|
||||
|
||||
Future<Response> _createPosition(Request request) async {
|
||||
final body = await request.readAsString();
|
||||
final data = jsonDecode(body);
|
||||
|
||||
final userId = data['user_id'];
|
||||
final x = data['x'];
|
||||
final y = data['y'];
|
||||
final lifetimeSeconds = data['lifetime'];
|
||||
final lifetime = Duration(seconds: lifetimeSeconds);
|
||||
|
||||
final position = await database.createPosition(userId, x, y, lifetime);
|
||||
return Response(201, body: position.toJson());
|
||||
}
|
||||
|
||||
Future<Response> _updatePosition(Request request) async {
|
||||
final body = await request.readAsString();
|
||||
final data = jsonDecode(body);
|
||||
|
||||
final userId = data['user_id'];
|
||||
final x = data['x'];
|
||||
final y = data['y'];
|
||||
final lifetimeSeconds = data['lifetime'];
|
||||
final lifetime = Duration(seconds: lifetimeSeconds);
|
||||
|
||||
final position = await database.updatePosition(userId, x, y, lifetime);
|
||||
return Response(200, body: position.toJson());
|
||||
}
|
||||
|
||||
Future<Response> _createShare(Request request) async {
|
||||
final body = await request.readAsString();
|
||||
final data = jsonDecode(body);
|
||||
|
||||
final userId = data['user_id'];
|
||||
final shareId = database.createShareId(userId);
|
||||
|
||||
return Response(200, body: jsonEncode({'share_id': shareId}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf_router/shelf_router.dart';
|
||||
import '../database/database_provider.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class UserRoutes {
|
||||
final DatabaseProvider database;
|
||||
|
||||
UserRoutes(this.database);
|
||||
|
||||
Router get routes {
|
||||
final router = Router();
|
||||
router.get('/user', _getAllUsers);
|
||||
router.post('/user', _createUser);
|
||||
router.put('/user/<id>', _updateUser);
|
||||
router.delete('/user/<id>', _deleteUser);
|
||||
return router;
|
||||
}
|
||||
|
||||
Future<Response> _getAllUsers(Request request) async {
|
||||
final users = await database.getAllUsers();
|
||||
return Response(200, body: jsonEncode(users.map((u) => u.toMap()).toList()));
|
||||
}
|
||||
|
||||
Future<Response> _createUser(Request request) async {
|
||||
final body = await request.readAsString();
|
||||
final data = jsonDecode(body);
|
||||
|
||||
final login = data['login'];
|
||||
final password = data['password'];
|
||||
|
||||
final user = await database.createUser(login, password);
|
||||
return Response(201, body: jsonEncode(user.toMap()));
|
||||
}
|
||||
|
||||
Future<Response> _updateUser(Request request) async {
|
||||
final id = int.parse(request.params['id']!);
|
||||
|
||||
final body = await request.readAsString();
|
||||
final data = jsonDecode(body);
|
||||
|
||||
final login = data['login'];
|
||||
final password = data['password'];
|
||||
|
||||
final user = await database.updateUser(id, login, password);
|
||||
return Response(200, body: jsonEncode(user.toMap()));
|
||||
}
|
||||
|
||||
Future<Response> _deleteUser(Request request) async {
|
||||
final id = int.parse(request.params['id']!);
|
||||
await database.deleteUser(id);
|
||||
return Response(204);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'dart:io';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf/shelf_io.dart';
|
||||
import 'package:shelf_router/shelf_router.dart';
|
||||
|
||||
import 'database/database_provider.dart';
|
||||
import 'routes/auth_routes.dart';
|
||||
import 'routes/user_routes.dart';
|
||||
import 'routes/geo_routes.dart';
|
||||
|
||||
void main(List<String> args) async {
|
||||
final database = DatabaseProvider();
|
||||
await database.initialize();
|
||||
|
||||
Timer.periodic(const Duration(minutes: 5), (timer) {
|
||||
database.cleanupExpired();
|
||||
});
|
||||
|
||||
final authRoutes = AuthRoutes(database);
|
||||
final userRoutes = UserRoutes(database);
|
||||
final geoRoutes = GeoRoutes(database);
|
||||
|
||||
final router = Router()
|
||||
..mount('', authRoutes.routes.call)
|
||||
..mount('', userRoutes.routes.call)
|
||||
..mount('', geoRoutes.routes.call)
|
||||
..get('/', (Request req) => Response.ok('Family Safety Tracker API\n'));
|
||||
|
||||
final handler = Pipeline()
|
||||
.addMiddleware(logRequests())
|
||||
.addHandler(router.call);
|
||||
|
||||
final ip = InternetAddress.anyIPv4;
|
||||
final port = int.parse(Platform.environment['PORT'] ?? '8080');
|
||||
final server = await serve(handler, ip, port);
|
||||
print('Server listening on port ${server.port}');
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"llama.cpp": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "llama-server (local)",
|
||||
"options": {
|
||||
"baseURL": "http://127.0.0.1:9988/v1"
|
||||
},
|
||||
"models": {
|
||||
"qwen3-coder:a3b": {
|
||||
"name": "Qwen_Qwen3.5-9B-Q6_K (local)",
|
||||
"limit": {
|
||||
"context": 42000,
|
||||
"output": 42000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"IntelliJIdea": {
|
||||
"type": "remote",
|
||||
"url": "http://127.0.0.1:64342/stream",
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+517
@@ -0,0 +1,517 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: a49d6cf99e8d8e7a8e93668d09ced0bbdb954d0b4fccc2f5f9241c6b87fad95c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "99.0.0"
|
||||
adaptive_number:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: adaptive_number
|
||||
sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "663efa951fb8a45e06f491223a604c93820598f20e6a99c25617a1576065e8b7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.1.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.1"
|
||||
bcrypt:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: bcrypt
|
||||
sha256: "6073a700cbbc59f1d4ab27cd532755e3de5e676c4941f535f351374df849270b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
buffer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: buffer
|
||||
sha256: "389da2ec2c16283c8787e0adaede82b1842102f8c8aae2f49003a766c5c6b3d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.3"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
cli_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_config
|
||||
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
coverage:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
dart_jsonwebtoken:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dart_jsonwebtoken
|
||||
sha256: "00a0812d2aeaeb0d30bcbc4dd3cee57971dbc0ab2216adf4f0247f37793f15ef"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.17.0"
|
||||
dotenv:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dotenv
|
||||
sha256: "379e64b6fc82d3df29461d349a1796ecd2c436c480d4653f3af6872eccbc90e1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
ed25519_edwards:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ed25519_edwards
|
||||
sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
http:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: http
|
||||
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
http_methods:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_methods
|
||||
sha256: "6bccce8f1ec7b5d701e7921dca35e202d425b57e317ba1a37f2638590e29e566"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: lints
|
||||
sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.20"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: df0c643f44ad098eb37988027a8e2b2b5a031fd3977f06bbfd3a76637e8df739
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.2"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: node_preamble
|
||||
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.9.1"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
postgres:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: postgres
|
||||
sha256: "3af8a28b89fef68ee5b26b4fd27254d5a286389e9c7fb6293a5f46e30490f800"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.5.10"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
shelf:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shelf
|
||||
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.2"
|
||||
shelf_packages_handler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_packages_handler
|
||||
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
shelf_router:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shelf_router
|
||||
sha256: f5e5d492440a7fb165fe1e2e1a623f31f734d3370900070b2b1e0d0428d59864
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.4"
|
||||
shelf_static:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_static
|
||||
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
source_map_stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_map_stack_trace
|
||||
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
source_maps:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_maps
|
||||
sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.10.13"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: ca578dc12bb8b2f40b67b7d3bd2fac4f31c01a6ff7130a14e2597b919934507f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.31.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.12"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: d2e98ec12998368dc59ddd47ab709f2cd55acd6b66dc7db764455a44082f4bc5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.18"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
uuid:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.3"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.2.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webkit_inspection_protocol
|
||||
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.10.1 <4.0.0"
|
||||
@@ -0,0 +1,21 @@
|
||||
name: family_safety_tracker
|
||||
description: A server app using the shelf package and Docker.
|
||||
version: 1.0.0
|
||||
# repository: https://github.com/my_org/my_repo
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.1
|
||||
|
||||
dependencies:
|
||||
shelf: ^1.4.2
|
||||
shelf_router: ^1.1.2
|
||||
dart_jsonwebtoken: ^2.16.0
|
||||
bcrypt: ^1.2.0
|
||||
dotenv: ^4.1.0
|
||||
postgres: ^3.5.10
|
||||
uuid: ^4.5.0
|
||||
|
||||
dev_dependencies:
|
||||
http: ^1.2.2
|
||||
lints: ^6.0.0
|
||||
test: ^1.25.6
|
||||
@@ -0,0 +1,39 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
final port = '8080';
|
||||
final host = 'http://0.0.0.0:$port';
|
||||
late Process p;
|
||||
|
||||
setUp(() async {
|
||||
p = await Process.start(
|
||||
'dart',
|
||||
['run', 'bin/server.dart'],
|
||||
environment: {'PORT': port},
|
||||
);
|
||||
// Wait for server to start and print to stdout.
|
||||
await p.stdout.first;
|
||||
});
|
||||
|
||||
tearDown(() => p.kill());
|
||||
|
||||
test('Root', () async {
|
||||
final response = await get(Uri.parse('$host/'));
|
||||
expect(response.statusCode, 200);
|
||||
expect(response.body, 'Hello, World!\n');
|
||||
});
|
||||
|
||||
test('Echo', () async {
|
||||
final response = await get(Uri.parse('$host/echo/hello'));
|
||||
expect(response.statusCode, 200);
|
||||
expect(response.body, 'hello\n');
|
||||
});
|
||||
|
||||
test('404', () async {
|
||||
final response = await get(Uri.parse('$host/foobar'));
|
||||
expect(response.statusCode, 404);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import 'package:bcrypt/bcrypt.dart';
|
||||
|
||||
void main() {
|
||||
print(BCrypt);
|
||||
}
|
||||
Reference in New Issue
Block a user