Boilerplate more or less complete
This commit is contained in:
parent
d9e8ce3bba
commit
7b91dd71dc
9 changed files with 130 additions and 47 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -73,3 +73,4 @@ crashlytics.properties
|
|||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
logs/**/*.txt
|
|
@ -4,16 +4,24 @@ part of angel.routes.controllers;
|
|||
class AuthController extends Controller {
|
||||
@override
|
||||
call(Angel app) async {
|
||||
await super.call(app);
|
||||
|
||||
app.registerMiddleware("auth", (req, res) async {
|
||||
if (req.session['userId'] == null)
|
||||
throw new AngelHttpException.Forbidden();
|
||||
if (!loggedIn(req)) throw new AngelHttpException.Forbidden();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool loggedIn(RequestContext req) => req.session["userId"] != null;
|
||||
|
||||
@Expose("/login", method: "POST")
|
||||
login(RequestContext req) async {
|
||||
// Include log-in logic here...
|
||||
}
|
||||
|
||||
@Expose("/register", method: "POST")
|
||||
register(RequestContext req, UserService Users) async {
|
||||
// And your registration logic...
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ library angel.routes.controllers;
|
|||
|
||||
import 'package:angel_auth/angel_auth.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import '../../services/user/user.dart';
|
||||
part 'auth.dart';
|
||||
|
||||
configureServer(Angel app) async {
|
||||
|
|
|
@ -15,18 +15,18 @@ configureRoutes(Angel app) async {
|
|||
|
||||
configureAfter(Angel app) async {
|
||||
// 404 handler
|
||||
app.after.add((RequestContext req, ResponseContext res) async {
|
||||
res.willCloseItself = true;
|
||||
res.status(404);
|
||||
res.header('Content-Type', 'text/html');
|
||||
res.underlyingResponse
|
||||
.write(await app.viewGenerator('404', {'path': req.path}));
|
||||
await res.underlyingResponse.close();
|
||||
});
|
||||
app.after.add((req, res) async => res
|
||||
..status(404)
|
||||
..render("404", {"path": req.path}));
|
||||
|
||||
// Default error handler
|
||||
app.onError(
|
||||
(e, req, res) async => res.render("error", {"message": e.message}));
|
||||
}
|
||||
|
||||
configureServer(Angel app) async {
|
||||
await configureBefore(app);
|
||||
await configureRoutes(app);
|
||||
await app.configure(Controllers.configureServer);
|
||||
await configureAfter(app);
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ library angel.services;
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:mongo_dart/mongo_dart.dart';
|
||||
|
||||
import 'users/users.dart' as Users;
|
||||
import 'user/user.dart' as User;
|
||||
|
||||
configureServer(Angel app) async {
|
||||
Db db = new Db(app.properties["mongo_db"]);
|
||||
await db.open();
|
||||
|
||||
await app.configure(Users.configureServer(db));
|
||||
await app.configure(User.configureServer(db));
|
||||
}
|
||||
|
|
59
lib/src/services/user/user.dart
Normal file
59
lib/src/services/user/user.dart
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -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
49
views/error.mustache
Normal 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>
|
Loading…
Reference in a new issue