Boilerplate more or less complete

This commit is contained in:
thosakwe 2016-09-21 01:44:56 -04:00
parent d9e8ce3bba
commit 7b91dd71dc
9 changed files with 130 additions and 47 deletions

1
.gitignore vendored
View file

@ -73,3 +73,4 @@ crashlytics.properties
crashlytics-build.properties crashlytics-build.properties
fabric.properties fabric.properties
logs/**/*.txt

View file

@ -4,16 +4,24 @@ part of angel.routes.controllers;
class AuthController extends Controller { class AuthController extends Controller {
@override @override
call(Angel app) async { call(Angel app) async {
await super.call(app);
app.registerMiddleware("auth", (req, res) async { app.registerMiddleware("auth", (req, res) async {
if (req.session['userId'] == null) if (!loggedIn(req)) throw new AngelHttpException.Forbidden();
throw new AngelHttpException.Forbidden();
return true; return true;
}); });
} }
bool loggedIn(RequestContext req) => req.session["userId"] != null;
@Expose("/login", method: "POST") @Expose("/login", method: "POST")
login(RequestContext req) async { login(RequestContext req) async {
// Include log-in logic here... // Include log-in logic here...
} }
@Expose("/register", method: "POST")
register(RequestContext req, UserService Users) async {
// And your registration logic...
}
} }

View file

@ -2,6 +2,7 @@ library angel.routes.controllers;
import 'package:angel_auth/angel_auth.dart'; import 'package:angel_auth/angel_auth.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import '../../services/user/user.dart';
part 'auth.dart'; part 'auth.dart';
configureServer(Angel app) async { configureServer(Angel app) async {

View file

@ -15,18 +15,18 @@ configureRoutes(Angel app) async {
configureAfter(Angel app) async { configureAfter(Angel app) async {
// 404 handler // 404 handler
app.after.add((RequestContext req, ResponseContext res) async { app.after.add((req, res) async => res
res.willCloseItself = true; ..status(404)
res.status(404); ..render("404", {"path": req.path}));
res.header('Content-Type', 'text/html');
res.underlyingResponse // Default error handler
.write(await app.viewGenerator('404', {'path': req.path})); app.onError(
await res.underlyingResponse.close(); (e, req, res) async => res.render("error", {"message": e.message}));
});
} }
configureServer(Angel app) async { configureServer(Angel app) async {
await configureBefore(app); await configureBefore(app);
await configureRoutes(app); await configureRoutes(app);
await app.configure(Controllers.configureServer);
await configureAfter(app); await configureAfter(app);
} }

View file

@ -4,11 +4,11 @@ library angel.services;
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'package:mongo_dart/mongo_dart.dart'; import 'package:mongo_dart/mongo_dart.dart';
import 'users/users.dart' as Users; import 'user/user.dart' as User;
configureServer(Angel app) async { configureServer(Angel app) async {
Db db = new Db(app.properties["mongo_db"]); Db db = new Db(app.properties["mongo_db"]);
await db.open(); await db.open();
await app.configure(Users.configureServer(db)); await app.configure(User.configureServer(db));
} }

View file

@ -0,0 +1,59 @@
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_mongo/angel_mongo.dart';
import 'package:crypto/crypto.dart' show sha256;
import 'package:mongo_dart/mongo_dart.dart';
import 'package:validate/validate.dart';
import '../../models/user.dart';
export '../../models/user.dart';
configureServer(Db db) {
return (Angel app) async {
app.use("/api/users", new UserService(db.collection("users")));
HookedService service = app.service("api/users");
app.container.singleton(service.inner);
};
}
/// Manages users.
///
/// Here, we extended the base service class. This allows to only expose
/// specific methods, and also allows more freedom over things such as validation.
class UserService extends Service {
MongoTypedService<User> _inner;
UserService(DbCollection collection):super() {
_inner = new MongoTypedService<User>(collection);
}
@override
index([Map params]) {
if (params != null && params.containsKey("provider")) {
// Nobody needs to see the entire user list except for the server.
throw new AngelHttpException.Forbidden();
}
return _inner.index(params);
}
@override
create(data, [Map params]) {
if (params != null && params.containsKey("provider")) {
// Deny creating users to the public - this should be done by the server only.
throw new AngelHttpException.Forbidden();
}
try {
Validate.isKeyInMap("username", data);
Validate.isEmail(data["email"]);
data["password"] = sha256.convert(data["password"].codeUnits).toString();
} catch(e) {
throw new AngelHttpException.BadRequest(message: "User must have a username, e-mail address and password.");
}
return _inner.create(data, params);
}
@override
read(id, [Map params]) => _inner.read(id, params);
}

View file

@ -1,32 +0,0 @@
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_mongo/angel_mongo.dart';
import 'package:crypto/crypto.dart' show sha256;
import 'package:mongo_dart/mongo_dart.dart';
import 'package:validate/validate.dart';
import '../../models/user.dart';
hashPassword(HookedServiceEvent event) {
if (event.data.password != null) {
event.data.password =
sha256.convert(event.data.password.codeUnits).toString();
}
}
configureServer(Db db) {
return (Angel app) async {
app.use("/api/users", new MongoTypedService<User>(db.collection("users")));
HookedService service = app.service("api/users");
// Place your hooks here!
service.beforeCreated.listen((HookedServiceEvent e) {
Validate.isKeyInMap("username", e.data);
Validate.isEmail(e.data["email"]);
Validate.isPassword(e.data["password"]);
});
service.beforeCreated.listen(hashPassword);
};
}

View file

@ -1,3 +0,0 @@
INFO: 2016-09-20 00:52:14.862305: Server listening at http://127.0.0.1:3000
CONFIG: 2016-09-20 00:52:14.864663: Starting server with given configuration: {mongo_db: mongodb://localhost:27017/angel, db: {web: {database: angel, password: password, username: username}, migrate: {database: angel, password: password, username: root}}, host: 127.0.0.1, port: 3000}
INFO: 2016-09-20 00:52:20.711300: 200 GET / (69 ms)

49
views/error.mustache Normal file
View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<title>{{message}}</title>
<link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css">
<style>
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;
}
.subtitle {
font-size: 32px;
}
</style>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">{{message}}</div>
</div>
</div>
</body>
</html>