feat: change api framework to angel3.

pull/5/head
DebuggerX 3 years ago
parent 8face6f724
commit ed863ecb41

@ -0,0 +1,10 @@
.dart_tool
.idea
.pub
.vscode
logs/
test/
build/
.analysis-options
.packages
*.g.dart

99
api/.gitignore vendored

@ -1,28 +1,95 @@
# Created by .ignore support plugin (hsz.mobi)
### Dart template
# See https://www.dartlang.org/guides/libraries/private-files
# See https://www.dartlang.org/tools/private-files.html
# source_gen
.dart_tool
# Files and directories created by pub
.dart_tool/
.buildlog
.packages
.project
.pub/
.scripts-bin/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
**/packages/
# Avoid committing generated Javascript files:
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.info.json # Produced by the --dump-info flag.
*.js # When generated by dart2js. Don't specify *.js if your
# project includes source files written in JavaScript.
*.js_
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
doc/api/
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
pubspec.lock
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
# Mongo Explorer plugin:
.idea/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### VSCode template
.vscode/
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
logs/
*.pem
.DS_Store
server_log.txt
.flutter-plugins
.flutter-plugins-dependencies
.metals/
config.yaml
/config/production.yaml
/config/development.yaml

@ -0,0 +1,12 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

@ -0,0 +1,9 @@
# Change Log
## 1.0.0
* Changed to use `angel3` packages
* Updated to support NNBD
* Updated README
* Updated default `postgresql` setup
* Updated linter to `package:lints`

@ -0,0 +1,24 @@
# Contribution
Any help from the open-source community is always welcome and needed:
1. Found an issue?
- Please [fill a bug report][tracker] with error message and steps to reproduce it.
2. Wish a feature?
- Open a feature request with use cases.
3. Are you using and liking the project?
- Create an article about your use case
- Do a post on your likes and dislikes
- Make a donation.
4. Are you a developer?
- Fix a bug and send a [pull request][pull_request]
- Implement a new feature
- Improve the Unit Tests
- Improve the [User Guide][doc] and send a [document pull request][doc_repo]
5. Have you already helped in any way?
- **Many thanks to the contributors and everybody that uses this project!**
[tracker]: https://github.com/dukefirehawk/angel/issues
[pull_request]: https://github.com/dukefirehawk/angel/pulls
[doc]: https://angel3-docs.dukefirehawk.com
[doc_repo]: https://github.com/dukefirehawk/angel3-guide/pulls

@ -0,0 +1,14 @@
FROM google/dart:latest
COPY ./ ./
# Install dependencies, pre-build
RUN pub get
# Optionally build generaed sources.
# RUN pub run build_runner build
# Set environment, start server
ENV ANGEL_ENV=production
EXPOSE 3000
CMD dart bin/prod.dart

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -1,37 +1,62 @@
# dde_gesture_manager
# ORM Starter Application for Angel3 framework
## Running the Application Locally
This is an ORM starter application for [Angel3 framework](https://angel3-framework.web.app) which is a full-stack Web framework in Dart. The default database is `postgresql`. `mysql` support is still in active development.
Run `conduit serve` from this directory to run the application. For running within an IDE, run `bin/main.dart`. By default, a configuration file named `config.yaml` will be used.
## Installation & Setup
You must have a `config.yaml` file that has correct database connection info, which should point to a local database. To configure a database to match your application's schema, run the following commands:
1. Download and install [Dart](https://dart.dev/get-dart).
2. Install `postgresql` version 9, 10, 11 or 12. **postgresql 13 is not working as the driver do not support SCRAM**
3. Create a new user and database in postgres using `psql` cli. For example:
```
# if this is a project, run db generate first
conduit db generate
conduit db upgrade --connect postgres://user:password@localhost:5432/app_name
```
```sql
postgres=# create database appdb;
postgres=# create user appuser with encrypted password 'App1970#';
postgres=# grant all privileges on database appdb to appuser;
```
To generate a SwaggerUI client, run `conduit document client`.
4. Update the `postgres` section in the `config/default.yaml` file with the newly created user and database name.
## Running Application Tests
```yaml
postgres:
host: localhost
port: 5432
database_name: appdb
username: appuser
password: App1970#
useSSL: false
time_zone: UTC
```
Tests are run with a local PostgreSQL database named `conduit_test_db`. If this database does not exist, create it from your SQL prompt:
5. Run the migration to generate `migrations` and `greetings` tables in the database.
CREATE DATABASE conduit_test_db;
CREATE USER conduit_test_user WITH createdb;
ALTER USER conduit_test_user WITH password 'conduit!';
GRANT all ON DATABASE conduit_test_db TO conduit_test_user;
```bash
dart bin/migration.dart
```
### Development
To run all tests for this application, run the following in this directory:
1. Run the following command to start Angel3 server in dev mode to *hot-reloaded* on file changes:
```
pub run test
```
```bash
dart --observe bin/dev.dart
```
The default configuration file used when testing is `config.src.yaml`. This file should be checked into version control. It also the template for configuration files used in deployment.
2. Modify the code and watch the changes applied to the application
## Deploying an Application
### Production
See the documentation for [Deployment](https://conduit.io/docs/deploy/).
1. Run the following command:
```bash
dart bin/prod.dart
```
2. Run as docker. Edit and run the provided `Dockerfile` to build the image.
## Resources
Visit the [Developer Guide](https://angel3-docs.dukefirehawk.com/guides) for dozens of guides and resources, including video tutorials, to get up and running as quickly as possible with Angel3.
Examples and complete projects can be found [here](https://angel3-framework.web.app/#/examples).
You can also view the [API Documentation](https://pub.dev/documentation/angel3_framework/latest/).

@ -1,98 +1,6 @@
analyzer:
strong-mode:
implicit-casts: false
include: package:lints/recommended.yaml
linter:
rules:
- always_declare_return_types
- always_put_control_body_on_new_line
- always_put_required_named_parameters_first
- always_require_non_null_named_parameters
- annotate_overrides
- avoid_bool_literals_in_conditional_expressions
- avoid_double_and_int_checks
- avoid_empty_else
- avoid_field_initializers_in_const_classes
- avoid_init_to_null
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_single_cascade_in_expression_statements
- avoid_slow_async_io
- avoid_types_as_parameter_names
- avoid_unused_constructor_parameters
- await_only_futures
- camel_case_types
- cancel_subscriptions
- close_sinks
- comment_references
- constant_identifier_names
- control_flow_in_finally
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
- hash_and_equals
- implementation_imports
- invariant_booleans
- iterable_contains_unrelated_type
- join_return_with_assignment
- library_names
- library_prefixes
- list_remove_unrelated_type
- literal_only_boolean_expressions
- no_duplicate_case_values
- non_constant_identifier_names
- null_closures
- package_api_docs
- package_names
- package_prefixed_library_names
- parameter_assignments
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_collection_literals
- prefer_conditional_assignment
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
- prefer_final_fields
- prefer_final_locals
- prefer_foreach
- prefer_generic_function_type_aliases
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_iterable_whereType
- prefer_typing_uninitialized_variables
- recursive_getters
- slash_for_doc_comments
- sort_constructors_first
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
- type_annotate_public_apis
- type_init_formals
- unawaited_futures
- unnecessary_const
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_new
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_statements
- unnecessary_this
- unrelated_type_equality_checks
- use_rethrow_when_possible
- use_string_buffers
- use_to_and_as_if_applicable
- valid_regexps
- void_checks
avoid_renaming_method_parameters: false
overridden_fields: false

@ -0,0 +1,28 @@
import 'dart:io';
import 'package:dde_gesture_manager_api/dde_gesture_manager_api.dart';
import 'package:belatuk_pretty_logging/belatuk_pretty_logging.dart';
import 'package:angel3_container/mirrors.dart';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_hot/angel3_hot.dart';
import 'package:logging/logging.dart';
void main() async {
// Watch the config/ and web/ directories for changes, and hot-reload the server.
hierarchicalLoggingEnabled = true;
var hot = HotReloader(() async {
var logger = Logger.detached('dde_gesture_manager_api')
..level = Level.ALL
..onRecord.listen(prettyLog);
var app = Angel(logger: logger, reflector: MirrorsReflector());
await app.configure(configureServer);
return app;
}, [
Directory('config'),
Directory('lib'),
]);
var server = await hot.startServer('127.0.0.1', 3000);
print(
'dde_gesture_manager_api server listening at http://${server.address.address}:${server.port}');
}

@ -1,13 +0,0 @@
import 'package:dde_gesture_manager/dde_gesture_manager.dart';
Future main() async {
final app = Application<DdeGestureManagerChannel>()
..options.configurationFilePath = "config.yaml"
..options.port = 8888;
await app.startOnCurrentIsolate();
print("Application started on port: ${app.options.port}.");
print("Click to open in browser: http://localhost:${app.options.port}");
print("Use Ctrl-C (SIGINT) to stop running the application.");
}

@ -0,0 +1,28 @@
import 'package:dde_gesture_manager_api/src/config/plugins/orm.dart';
import 'package:dde_gesture_manager_api/models.dart';
import 'package:angel3_configuration/angel3_configuration.dart';
import 'package:angel3_migration_runner/angel3_migration_runner.dart';
import 'package:angel3_migration_runner/postgres.dart';
import 'package:file/local.dart';
import 'package:logging/logging.dart';
void main(List<String> args) async {
// Enable the logging
Logger.root.level = Level.INFO;
Logger.root.onRecord.listen((rec) {
print('${rec.time}: ${rec.level.name}: ${rec.loggerName}: ${rec.message}');
if (rec.error != null) {
print(rec.error);
print(rec.stackTrace);
}
});
var fs = LocalFileSystem();
var configuration = await loadStandaloneConfiguration(fs);
var connection = await connectToPostgres(configuration);
var migrationRunner = PostgresMigrationRunner(connection, migrations: [
UserMigration(),
]);
await runMigrations(migrationRunner, args);
}

@ -0,0 +1,27 @@
import 'package:dde_gesture_manager_api/dde_gesture_manager_api.dart';
import 'package:angel3_production/angel3_production.dart';
// NOTE: By default, the Runner class does not use the `MirrorsReflector`, or any
// reflector, by default.
//
// If your application is using any sort of functionality reliant on annotations or reflection,
// either include the MirrorsReflector, or use a static reflector variant.
//
// The following use cases require reflection:
// * Use of Controllers, via @Expose() or @ExposeWS()
// * Use of dependency injection into constructors, whether in controllers or plain `container.make` calls
// * Use of the `ioc` function in any route
//
// The `MirrorsReflector` from `package:angel_container/mirrors.dart` is by far the most convenient pattern,
// so use it if possible.
//
// However, the following alternatives exist:
// * Generation via `package:angel_container_generator`
// * Creating an instance of `StaticReflector`
// * Manually implementing the `Reflector` interface (cumbersome; not recommended)
//
// As of January 4th, 2018, the documentation has not yet been updated to state this,
// so in the meantime, visit the Angel chat for further questions:
//
// https://gitter.im/angel_dart/discussion
void main(List<String> args) => Runner('dde_gesture_manager_api', configureServer).run(args);

@ -1,6 +0,0 @@
database:
username: conduit_test_user
password: conduit!
host: localhost
port: 15432 # change this value
databaseName: conduit_test_db

@ -0,0 +1,12 @@
# Default server configuration.
host: 127.0.0.1
port: 3000
postgres:
host: localhost
port: 5432
database_name: appdb
username: appuser
password: App1970#
useSSL: false
time_zone: UTC
jwt_secret: "OvA9SBLnncot8gFHvt8Gh1qkQ1ptGIQW"

@ -1,77 +0,0 @@
import 'package:dde_gesture_manager/dde_gesture_manager.dart';
import 'package:dde_gesture_manager/model/model.dart';
/// This type initializes an application.
///
/// Override methods in this class to set up routes and initialize services like
/// database connections. See http://conduit.io/docs/http/channel/.
class DdeGestureManagerChannel extends ApplicationChannel {
late ManagedContext context;
/// Initialize services in this method.
///
/// Implement this method to initialize services, read values from [options]
/// and any other initialization required before constructing [entryPoint].
///
/// This method is invoked prior to [entryPoint] being accessed.
@override
Future prepare() async {
logger.onRecord.listen(
(rec) => print("$rec ${rec.error ?? ""} ${rec.stackTrace ?? ""}"));
final config =
DdeGestureManagerConfiguration(options!.configurationFilePath!);
context = contextWithConnectionInfo(config.database!);
}
/// Construct the request channel.
///
/// Return an instance of some [Controller] that will be the initial receiver
/// of all [Request]s.
///
/// This method is invoked after [prepare].
@override
Controller get entryPoint {
final router = Router();
router
.route("/model/[:id]")
.link(() => ManagedObjectController<Model>(context));
router
.route("/")
.linkFunction((Request request) async => Response.ok('ok'));
return router;
}
/*
* Helper methods
*/
ManagedContext contextWithConnectionInfo(
DatabaseConfiguration connectionInfo) {
final dataModel = ManagedDataModel.fromCurrentMirrorSystem();
final psc = PostgreSQLPersistentStore(
connectionInfo.username,
connectionInfo.password,
connectionInfo.host,
connectionInfo.port,
connectionInfo.databaseName);
return ManagedContext(dataModel, psc);
}
}
/// An instance of this class reads values from a configuration
/// file specific to this application.
///
/// Configuration files must have key-value for the properties in this class.
/// For more documentation on configuration files, see https://conduit.io/docs/configure/ and
/// https://pub.dartlang.org/packages/safe_config.
class DdeGestureManagerConfiguration extends Configuration {
DdeGestureManagerConfiguration(String fileName)
: super.fromFile(File(fileName));
DatabaseConfiguration? database;
}

@ -1,11 +0,0 @@
/// dde_gesture_manager
///
/// A conduit web server.
library dde_gesture_manager;
export 'dart:async';
export 'dart:io';
export 'package:conduit/conduit.dart';
export 'channel.dart';

@ -0,0 +1,17 @@
/// Your very own web application!
import 'dart:async';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:file/local.dart';
import 'src/config/config.dart' as configuration;
import 'src/routes/routes.dart' as routes;
/// Configures the server instance.
Future configureServer(Angel app) async {
// Grab a handle to the file system, so that we can do things like
// serve static files.
var fs = const LocalFileSystem();
// Set up our application, using the plug-ins defined with this project.
await app.configure(configuration.configureServer(fs));
await app.configure(routes.configureServer(fs));
}

@ -1,18 +0,0 @@
import 'package:dde_gesture_manager/dde_gesture_manager.dart';
class Model extends ManagedObject<_Model> implements _Model {
@override
void willInsert() {
createdAt = DateTime.now().toUtc();
}
}
class _Model {
@primaryKey
int? id;
@Column(indexed: true)
String? name;
DateTime? createdAt;
}

@ -0,0 +1 @@
export 'src/models/user.dart';

@ -0,0 +1,30 @@
import 'package:angel3_configuration/angel3_configuration.dart';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_jinja/angel3_jinja.dart';
import 'package:file/file.dart';
import 'plugins/plugins.dart' as plugins;
/// This is a perfect place to include configuration and load plug-ins.
AngelConfigurer configureServer(FileSystem fileSystem) {
return (Angel app) async {
// Load configuration from the `config/` directory.
//
// See: https://github.com/angel-dart/configuration
await app.configure(configuration(fileSystem));
// Configure our application to render jinja templates from the `views/` directory.
//
// See: https://github.com/angel-dart/jinja
await app.configure(jinja(path: fileSystem.directory('views').path));
// Apply another plug-ins, i.e. ones that *you* have written.
//
// Typically, the plugins in `lib/src/config/plugins/plugins.dart` are plug-ins
// that add functionality specific to your application.
//
// If you write a plug-in that you plan to use again, or are
// using one created by the community, include it in
// `lib/src/config/config.dart`.
await plugins.configureServer(app);
};
}

@ -0,0 +1,35 @@
import 'dart:async';
import 'dart:io';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_orm_postgres/angel3_orm_postgres.dart';
import 'package:postgres/postgres.dart';
Future<void> configureServer(Angel app) async {
var connection = await connectToPostgres(app.configuration);
await connection.open();
var logger = app.environment.isProduction ? null : app.logger;
var executor = PostgreSqlExecutor(connection, logger: logger);
app
..container!.registerSingleton<QueryExecutor>(executor)
..shutdownHooks.add((_) => connection.close());
}
Future<PostgreSQLConnection> connectToPostgres(Map configuration) async {
var postgresConfig = configuration['postgres'] as Map? ?? {};
var connection = PostgreSQLConnection(
postgresConfig['host'] as String? ?? 'localhost',
postgresConfig['port'] as int? ?? 5432,
postgresConfig['database_name'] as String? ??
Platform.environment['USER'] ??
Platform.environment['USERNAME'] ??
'',
username: postgresConfig['username'] as String?,
password: postgresConfig['password'] as String?,
timeZone: postgresConfig['time_zone'] as String? ?? 'UTC',
timeoutInSeconds: postgresConfig['timeout_in_seconds'] as int? ?? 30,
useSSL: postgresConfig['use_ssl'] as bool? ?? false);
return connection;
}

@ -0,0 +1,8 @@
import 'dart:async';
import 'package:angel3_framework/angel3_framework.dart';
import 'orm.dart' as orm;
Future configureServer(Angel app) async {
// Include any plugins you have made here.
await app.configure(orm.configureServer);
}

@ -0,0 +1,8 @@
import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
abstract class BaseModel extends Model {
@SerializableField(isNullable: true)
@Column(type: ColumnType.json)
Map<String, dynamic>? get metadata;
}

@ -0,0 +1,19 @@
import 'package:angel3_migration/angel3_migration.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:angel3_orm/angel3_orm.dart';
import 'package:dde_gesture_manager_api/src/models/base_model.dart';
import 'package:optional/optional.dart';
part 'user.g.dart';
@serializable
@orm
abstract class _User extends BaseModel {
@SerializableField(isNullable: false)
String? get email;
@SerializableField(isNullable: false)
String? get password;
@SerializableField(isNullable: false)
String? get token;
}

@ -0,0 +1,369 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// MigrationGenerator
// **************************************************************************
class UserMigration extends Migration {
@override
void up(Schema schema) {
schema.create('users', (table) {
table.serial('id').primaryKey();
table.timeStamp('created_at');
table.timeStamp('updated_at');
table.declareColumn(
'metadata', Column(type: ColumnType('jsonb'), length: 256));
table.varChar('email', length: 256);
table.varChar('password', length: 256);
table.varChar('token', length: 256);
});
}
@override
void down(Schema schema) {
schema.drop('users');
}
}
// **************************************************************************
// OrmGenerator
// **************************************************************************
class UserQuery extends Query<User, UserQueryWhere> {
UserQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
trampoline ??= <String>{};
trampoline.add(tableName);
_where = UserQueryWhere(this);
}
@override
final UserQueryValues values = UserQueryValues();
UserQueryWhere? _where;
@override
Map<String, String> get casts {
return {};
}
@override
String get tableName {
return 'users';
}
@override
List<String> get fields {
return const [
'id',
'created_at',
'updated_at',
'metadata',
'email',
'password',
'token'
];
}
@override
UserQueryWhere? get where {
return _where;
}
@override
UserQueryWhere newWhereClause() {
return UserQueryWhere(this);
}
static User? parseRow(List row) {
if (row.every((x) => x == null)) {
return null;
}
var model = User(
id: row[0].toString(),
createdAt: (row[1] as DateTime?),
updatedAt: (row[2] as DateTime?),
metadata: (row[3] as Map<String, dynamic>?),
email: (row[4] as String?),
password: (row[5] as String?),
token: (row[6] as String?));
return model;
}
@override
Optional<User> deserialize(List row) {
return Optional.ofNullable(parseRow(row));
}
}
class UserQueryWhere extends QueryWhere {
UserQueryWhere(UserQuery query)
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'),
updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'),
metadata = MapSqlExpressionBuilder(query, 'metadata'),
email = StringSqlExpressionBuilder(query, 'email'),
password = StringSqlExpressionBuilder(query, 'password'),
token = StringSqlExpressionBuilder(query, 'token');
final NumericSqlExpressionBuilder<int> id;
final DateTimeSqlExpressionBuilder createdAt;
final DateTimeSqlExpressionBuilder updatedAt;
final MapSqlExpressionBuilder metadata;
final StringSqlExpressionBuilder email;
final StringSqlExpressionBuilder password;
final StringSqlExpressionBuilder token;
@override
List<SqlExpressionBuilder> get expressionBuilders {
return [id, createdAt, updatedAt, metadata, email, password, token];
}
}
class UserQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {};
}
String? get id {
return (values['id'] as String?);
}
set id(String? value) => values['id'] = value;
DateTime? get createdAt {
return (values['created_at'] as DateTime?);
}
set createdAt(DateTime? value) => values['created_at'] = value;
DateTime? get updatedAt {
return (values['updated_at'] as DateTime?);
}
set updatedAt(DateTime? value) => values['updated_at'] = value;
Map<String, dynamic>? get metadata {
return (values['metadata'] as Map<String, dynamic>?);
}
set metadata(Map<String, dynamic>? value) => values['metadata'] = value;
String? get email {
return (values['email'] as String?);
}
set email(String? value) => values['email'] = value;
String? get password {
return (values['password'] as String?);
}
set password(String? value) => values['password'] = value;
String? get token {
return (values['token'] as String?);
}
set token(String? value) => values['token'] = value;
void copyFrom(User model) {
createdAt = model.createdAt;
updatedAt = model.updatedAt;
metadata = model.metadata;
email = model.email;
password = model.password;
token = model.token;
}
}
// **************************************************************************
// JsonModelGenerator
// **************************************************************************
@generatedSerializable
class User extends _User {
User(
{this.id,
this.createdAt,
this.updatedAt,
Map<String, dynamic>? metadata,
required this.email,
required this.password,
required this.token})
: metadata = Map.unmodifiable(metadata ?? {});
/// A unique identifier corresponding to this item.
@override
String? id;
/// The time at which this item was created.
@override
DateTime? createdAt;
/// The last time at which this item was updated.
@override
DateTime? updatedAt;
@override
Map<String, dynamic>? metadata;
@override
String? email;
@override
String? password;
@override
String? token;
User copyWith(
{String? id,
DateTime? createdAt,
DateTime? updatedAt,
Map<String, dynamic>? metadata,
String? email,
String? password,
String? token}) {
return User(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
metadata: metadata ?? this.metadata,
email: email ?? this.email,
password: password ?? this.password,
token: token ?? this.token);
}
@override
bool operator ==(other) {
return other is _User &&
other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
MapEquality<String, dynamic>(
keys: DefaultEquality<String>(), values: DefaultEquality())
.equals(other.metadata, metadata) &&
other.email == email &&
other.password == password &&
other.token == token;
}
@override
int get hashCode {
return hashObjects(
[id, createdAt, updatedAt, metadata, email, password, token]);
}
@override
String toString() {
return 'User(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, metadata=$metadata, email=$email, password=$password, token=$token)';
}
Map<String, dynamic> toJson() {
return UserSerializer.toMap(this);
}
}
// **************************************************************************
// SerializerGenerator
// **************************************************************************
const UserSerializer userSerializer = UserSerializer();
class UserEncoder extends Converter<User, Map> {
const UserEncoder();
@override
Map convert(User model) => UserSerializer.toMap(model);
}
class UserDecoder extends Converter<Map, User> {
const UserDecoder();
@override
User convert(Map map) => UserSerializer.fromMap(map);
}
class UserSerializer extends Codec<User, Map> {
const UserSerializer();
@override
UserEncoder get encoder => const UserEncoder();
@override
UserDecoder get decoder => const UserDecoder();
static User fromMap(Map map) {
if (map['email'] == null) {
throw FormatException("Missing required field 'email' on User.");
}
if (map['password'] == null) {
throw FormatException("Missing required field 'password' on User.");
}
if (map['token'] == null) {
throw FormatException("Missing required field 'token' on User.");
}
return User(
id: map['id'] as String?,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null,
metadata: map['metadata'] is Map
? (map['metadata'] as Map).cast<String, dynamic>()
: {},
email: map['email'] as String?,
password: map['password'] as String?,
token: map['token'] as String?);
}
static Map<String, dynamic> toMap(_User? model) {
if (model == null) {
return {};
}
return {
'id': model.id,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String(),
'metadata': model.metadata,
'email': model.email,
'password': model.password,
'token': model.token
};
}
}
abstract class UserFields {
static const List<String> allFields = <String>[
id,
createdAt,
updatedAt,
metadata,
email,
password,
token
];
static const String id = 'id';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
static const String metadata = 'metadata';
static const String email = 'email';
static const String password = 'password';
static const String token = 'token';
}

@ -0,0 +1,21 @@
import 'dart:io';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_orm/angel3_orm.dart' as orm;
extension ResponseNoContent on ResponseContext {
noContent() {
statusCode = HttpStatus.noContent;
return close();
}
}
extension QueryWhereId on orm.Query {
set whereId(int id) {
(where as dynamic).id.equals(id);
}
}
extension QueryExecutor on RequestContext {
orm.QueryExecutor get queryExecutor => container!.make<orm.QueryExecutor>();
}

@ -0,0 +1,16 @@
import 'dart:async';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:dde_gesture_manager_api/models.dart';
import 'controller_extensions.dart';
Future configureServer(Angel app) async {
app.get(
'/user/int:id',
(req, res) async {
var user = await (UserQuery()..where?.metadata.contains({"uid": req.params[UserFields.id]}))
.getOne(req.queryExecutor);
return res.json(user.value);
},
);
}

@ -0,0 +1,39 @@
import 'package:angel3_framework/angel3_framework.dart';
import 'package:file/file.dart';
import 'controllers/user_controllers.dart' as UserControllers;
/// Put your app routes here!
///
/// See the wiki for information about routing, requests, and responses:
/// * https://angel3-docs.dukefirehawk.com/guides/basic-routing
/// * https://angel3-docs.dukefirehawk.com/guides/requests-and-responses
AngelConfigurer configureServer(FileSystem fileSystem) {
return (Angel app) async {
// Typically, you want to mount controllers first, after any global middleware.
await app.configure(UserControllers.configureServer);
// Throw a 404 if no route matched the request.
app.fallback((req, res) => throw AngelHttpException.notFound());
// Set our application up to handle different errors.
//
// Read the following for documentation:
// * https://angel3-docs.dukefirehawk.com/guides/error-handling
var oldErrorHandler = app.errorHandler;
app.errorHandler = (e, req, res) async {
if (req.accepts('text/html', strict: true)) {
if (e.statusCode == 404 && req.accepts('text/html', strict: true)) {
await res.render('error.html', {'message': 'No router exists for ${req.uri}'});
} else {
return await res.render('error.html', {
'message': [e.message, '', e.stackTrace.toString().replaceAll('\n', '<br/>')].join('<br/>')
});
}
} else {
return await oldErrorHandler(e, req, res);
}
};
};
}

@ -1,13 +1,34 @@
name: dde_gesture_manager
description: An conduit application with a database connection and data model.
version: 0.0.1
name: dde_gesture_manager_api
version: 1.0.0
description: An ORM starter application for Angel3 framework
publish_to: none
environment:
sdk: ">=2.12.0 <3.0.0"
sdk: '>=2.12.0 <3.0.0'
dependencies:
conduit: ^3.0.0
angel3_auth: ^4.0.0
angel3_configuration: ^4.1.0
angel3_framework: ^4.2.0
angel3_migration: ^4.0.0
angel3_orm: ^4.0.0
angel3_orm_postgres: ^3.0.0
angel3_serialize: ^4.1.0
angel3_production: ^3.1.0
angel3_static: ^4.1.0
angel3_validate: ^4.0.0
belatuk_pretty_logging: ^4.0.0
optional: ^6.0.0
logging: ^1.0.0
dev_dependencies:
test: ^1.16.5
conduit_test: ^3.0.0
angel3_hot: ^4.2.0
angel3_jinja: ^2.0.1
angel3_migration_runner: ^4.0.0
angel3_orm_generator: ^4.1.0
angel3_serialize_generator: ^4.2.0
angel3_test: ^4.0.0
build_runner: ^2.0.3
io: ^1.0.0
test: ^1.17.5
lints: ^1.0.0

@ -0,0 +1,43 @@
import 'package:dde_gesture_manager_api/dde_gesture_manager_api.dart';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_test/angel3_test.dart';
import 'package:test/test.dart';
// Angel also includes facilities to make testing easier.
//
// `package:angel_test` ships a client that can test
// both plain HTTP and WebSockets.
//
// Tests do not require your server to actually be mounted on a port,
// so they will run faster than they would in other frameworks, where you
// would have to first bind a socket, and then account for network latency.
//
// See the documentation here:
// https://github.com/angel-dart/test
//
// If you are unfamiliar with Dart's advanced testing library, you can read up
// here:
// https://github.com/dart-lang/test
void main() async {
late TestClient client;
setUp(() async {
var app = Angel();
await app.configure(configureServer);
client = await connectTo(app);
});
tearDown(() async {
await client.close();
});
test('index returns 200', () async {
// Request a resource at the given path.
var response = await client.get(Uri.parse('/'));
// Expect a 200 response.
expect(response, hasStatus(200));
});
}

@ -1,38 +0,0 @@
import 'package:conduit_test/conduit_test.dart';
import 'package:dde_gesture_manager/dde_gesture_manager.dart';
export 'package:conduit/conduit.dart';
export 'package:conduit_test/conduit_test.dart';
export 'package:dde_gesture_manager/dde_gesture_manager.dart';
export 'package:test/test.dart';
/// A testing harness for dde_gesture_manager.
///
/// A harness for testing an conduit application. Example test file:
///
/// void main() {
/// Harness harness = Harness()..install();
///
/// test("GET /path returns 200", () async {
/// final response = await harness.agent.get("/path");
/// expectResponse(response, 200);
/// });
/// }
///
class Harness extends TestHarness<DdeGestureManagerChannel> with TestHarnessORMMixin {
@override
ManagedContext? get context => channel?.context;
@override
Future onSetUp() async {
await resetData();
}
@override
Future onTearDown() async {}
@override
Future seed() async {
// restore any static data. called by resetData.
}
}

@ -1,32 +0,0 @@
import 'harness/app.dart';
Future main() async {
final harness = Harness()..install();
tearDown(() async {
await harness.resetData();
});
test("POST /model", () async {
final response = await harness.agent!.post("/model", body: {"name": "Bob"});
expect(
response,
hasResponse(200,
body: {"id": isNotNull, "name": "Bob", "createdAt": isTimestamp}));
});
test("GET /model/:id returns previously created object", () async {
var response = await harness.agent!.post("/model", body: {"name": "Bob"});
final createdObject = response?.body.as();
response =
await harness.agent!.request("/model/${createdObject["id"]}").get();
expect(
response,
hasResponse(200, body: {
"id": createdObject["id"],
"name": createdObject["name"],
"createdAt": createdObject["createdAt"]
}));
});
}

@ -0,0 +1,5 @@
{% extends "layout.html" %}
{% block title %}Error{% endblock %}
{% block body %}
<p>Error: {{ message }}</p>
{% endblock %}

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

@ -0,0 +1,27 @@
html, body {
height: 100%;
}
body {
margin: 0;
padding: 0;
width: 100%;
display: table;
font-weight: 100;
font-family: 'Lato', sans-serif;
}
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@ -1,29 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<div class="container">
<h1>Login</h1>
<form action="{{path}}" method="POST">
<input type="hidden" name="state" value="{{state}}">
<input type="hidden" name="client_id" value="{{client_id}}">
<input type="hidden" name="response_type" value="code">
<div class="form-group">
<label for="username">User Name</label>
<input type="text" class="form-control" name="username" placeholder="Please enter your user name">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" placeholder="Please enter your password">
</div>
<button type="submit" class="btn btn-success">Login</button>
</form>
</div>
</body>
</html>

@ -0,0 +1,2 @@
User-agent: *
Disallow: /admin
Loading…
Cancel
Save