feat: create app and api projects.

This commit is contained in:
2021-09-12 22:24:21 +08:00
commit 01327ddfe0
34 changed files with 1187 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
# Created by .ignore support plugin (hsz.mobi)
### Dart template
# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
.packages
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/
# Avoid committing generated 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_
*.js.deps
*.js.map
.flutter-plugins
.flutter-plugins-dependencies
config.yaml
+37
View File
@@ -0,0 +1,37 @@
# dde_gesture_manager
## Running the Application Locally
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.
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:
```
# if this is a project, run db generate first
conduit db generate
conduit db upgrade --connect postgres://user:password@localhost:5432/app_name
```
To generate a SwaggerUI client, run `conduit document client`.
## Running Application Tests
Tests are run with a local PostgreSQL database named `conduit_test_db`. If this database does not exist, create it from your SQL prompt:
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;
To run all tests for this application, run the following in this directory:
```
pub run test
```
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.
## Deploying an Application
See the documentation for [Deployment](https://conduit.io/docs/deploy/).
+98
View File
@@ -0,0 +1,98 @@
analyzer:
strong-mode:
implicit-casts: false
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
+13
View File
@@ -0,0 +1,13 @@
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.");
}
+6
View File
@@ -0,0 +1,6 @@
database:
username: conduit_test_user
password: conduit!
host: localhost
port: 15432 # change this value
databaseName: conduit_test_db
+77
View File
@@ -0,0 +1,77 @@
import 'package:dde_gesture_manager/model/model.dart';
import 'package:dde_gesture_manager/dde_gesture_manager.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;
}
+11
View File
@@ -0,0 +1,11 @@
/// 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';
+18
View File
@@ -0,0 +1,18 @@
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;
}
+13
View File
@@ -0,0 +1,13 @@
name: dde_gesture_manager
description: An conduit application with a database connection and data model.
version: 0.0.1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
conduit: ^3.0.0
dev_dependencies:
test: ^1.16.5
conduit_test: ^3.0.0
+38
View File
@@ -0,0 +1,38 @@
import 'package:dde_gesture_manager/dde_gesture_manager.dart';
import 'package:conduit_test/conduit_test.dart';
export 'package:dde_gesture_manager/dde_gesture_manager.dart';
export 'package:conduit_test/conduit_test.dart';
export 'package:test/test.dart';
export 'package:conduit/conduit.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.
}
}
+32
View File
@@ -0,0 +1,32 @@
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"]
}));
});
}
+29
View File
@@ -0,0 +1,29 @@
<!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>