Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • car-app/appwrite-functions
1 result
Show changes
Commits on Source (2)
Showing
with 455 additions and 184 deletions
import 'package:api/model/requesting_user_details.dart';
import 'package:lib/lib.dart';
import 'package:api/model/calendar_event.dart'; import 'package:api/model/calendar_event.dart';
import 'package:api/model/team.dart';
import 'package:api/model/user.dart';
import 'package:lib/lib.dart';
class CalendarEventApiEndpoint extends CheckedDbApiEndpoint<CalendarEvent, CalendarEvent> {
final User requestingUser;
final Iterable<Team> requestingUserTeams;
class CalendarEventApiEndpoint extends DbApiEndpoint<CalendarEvent, CalendarEvent> { @override
final RequestingUserDetails requestingUser; Future<bool> Function(CalendarEvent) get createItemAllowed => _createItemAllowed;
@override
Future<bool> Function(CalendarEvent) get getItemAllowed => _getItemAllowed;
@override
Future<bool> Function(CalendarEvent, CalendarEvent) get updateItemAllowed => _updateItemAllowed;
@override
Future<bool> Function(CalendarEvent) get deleteItemAllowed => _deleteItemAllowed;
CalendarEventApiEndpoint({ CalendarEventApiEndpoint({
required super.database, required super.database,
required super.itemFromRequest, required super.itemFromRequest,
required super.itemToResponse, required super.itemToResponse,
required this.requestingUser, required this.requestingUser,
required this.requestingUserTeams,
}); });
@override Future<bool> _createItemAllowed(CalendarEvent item) {
Future<CalendarEvent> create(CalendarEvent item) { return Future.value(
if (!requestingUser.teamIds.contains(item.teamId)){ _isUserInTeam(item)
throw UnauthorizedException(); && _isUserOwner(item)
} );
if (requestingUser.userId != item.userId) {
throw UnauthorizedException();
}
return super.create(item);
} }
@override Future<bool> _getItemAllowed(CalendarEvent item) {
Future<CalendarEvent> getFromId(String id) async { return Future.value(
var item = await super.getFromId(id); _isUserInTeam(item)
);
if(requestingUser.userId != item.userId) {
throw UnauthorizedException();
}
return item;
} }
@override Future<bool> _updateItemAllowed(CalendarEvent item, CalendarEvent originalItem) {
Stream<CalendarEvent> getFromQueries(Iterable<String> queries) async* { return Future.value(
await for(var queryResult in super.getFromQueries(queries)) { item.id == originalItem.id
if (requestingUser.userId == queryResult.userId) { && _isUserInTeam(item)
yield queryResult; && _isUserOwner(item)
} && _isUserOwner(originalItem)
} );
} }
@override Future<bool> _deleteItemAllowed(CalendarEvent item) {
Stream<CalendarEvent> getAll() async* { return Future.value(
await for(var item in super.getAll()) { _isUserOwner(item)
if(requestingUser.userId == item.userId) { );
yield item;
}
}
} }
@override bool _isUserOwner(CalendarEvent item) {
Future<CalendarEvent> update(CalendarEvent item) async { return requestingUser.id == item.userId;
var routeId = item.id; }
if (routeId == null) {
throw RequiredArgumentMissing(RequestResponseVariables.idFieldName);
}
if (requestingUser.userId != item.userId) {
throw UnauthorizedException();
}
var dbItem = await getFromId(item.id!);
if (requestingUser.userId != dbItem.userId) {
throw UnauthorizedException();
}
return super.update(item); bool _isUserInTeam(CalendarEvent item) {
return requestingUserTeams.any((team) => team.id == item.teamId);
} }
} }
import 'package:api/model/debt.dart'; import 'package:api/model/debt.dart';
import 'package:api/model/user.dart';
import 'package:api/service/debt.dart'; import 'package:api/service/debt.dart';
import 'package:api/model/requesting_user_details.dart';
import 'package:lib/lib.dart'; import 'package:lib/lib.dart';
class DebtApiEndpoint extends ApiEndpoint { class DebtApiEndpoint extends ApiEndpoint {
final RequestingUserDetails requestingUser; final User requestingUser;
final DebtService debtService; final DebtService debtService;
final Map<String, dynamic> Function(Debt) itemToResponse; final Map<String, dynamic> Function(Debt) itemToResponse;
...@@ -17,7 +17,7 @@ class DebtApiEndpoint extends ApiEndpoint { ...@@ -17,7 +17,7 @@ class DebtApiEndpoint extends ApiEndpoint {
@override @override
Future<Map<String, dynamic>> handleGet(context) async { Future<Map<String, dynamic>> handleGet(context) async {
var items = await debtService.getDebt(requestingUser.userId).toList(); var items = await debtService.getDebt(requestingUser.id).where((e) => checkGetAllowed(e, requestingUser.id)).toList();
return listResponse(context, items, itemToResponse); return listResponse(context, items, itemToResponse);
} }
...@@ -32,4 +32,7 @@ class DebtApiEndpoint extends ApiEndpoint { ...@@ -32,4 +32,7 @@ class DebtApiEndpoint extends ApiEndpoint {
throw ApiActionForbiddenException("put", "debt"); throw ApiActionForbiddenException("put", "debt");
} }
bool checkGetAllowed(Debt debt, String userId) {
return debt.creditor == userId || debt.debtor == userId;
}
} }
import 'dart:async';
import 'package:api/model/payment/driven_distance_distributed.dart';
import 'package:api/model/route.dart';
import 'package:api/model/team.dart';
import 'package:api/model/user.dart';
import 'package:lib/lib.dart';
class DrivenDistanceDistributedPaymentApiEndpoint extends CheckedDbApiEndpoint<DrivenDistanceDistributedPayment, DrivenDistanceDistributedPayment> {
final User requestingUser;
final Iterable<Team> requestingUserTeams;
final Future<Route> Function(String) getRouteFromId;
@override
Future<bool> Function(DrivenDistanceDistributedPayment) get createItemAllowed => _createItemAllowed;
@override
Future<bool> Function(DrivenDistanceDistributedPayment) get getItemAllowed => _getItemAllowed;
@override
Future<bool> Function(DrivenDistanceDistributedPayment, DrivenDistanceDistributedPayment) get updateItemAllowed => _updateItemAllowed;
@override
Future<bool> Function(DrivenDistanceDistributedPayment) get deleteItemAllowed => _deleteItemAllowed;
DrivenDistanceDistributedPaymentApiEndpoint({
required super.database,
required super.itemFromRequest,
required super.itemToResponse,
required this.requestingUser,
required this.requestingUserTeams,
required this.getRouteFromId,
});
Future<bool> _createItemAllowed(DrivenDistanceDistributedPayment item) async {
return _isUserOwner(item)
&& _isUserInTeam(item)
&& _hasAtLeastOneRoute(item)
&& await _areRoutesInSameTeam(item)
&& _isAmountOk(item);
}
Future<bool> _getItemAllowed(DrivenDistanceDistributedPayment item) {
return Future.value(
_isUserInTeam(item)
);
}
Future<bool> _updateItemAllowed(DrivenDistanceDistributedPayment item, DrivenDistanceDistributedPayment originalItem) async {
return item.id == originalItem.id
&& _isUserOwner(item)
&& _isUserOwner(originalItem)
&& _isUserInTeam(item)
&& _hasAtLeastOneRoute(item)
&& await _areRoutesInSameTeam(item)
&& _isAmountOk(item);
}
Future<bool> _deleteItemAllowed(DrivenDistanceDistributedPayment item) {
return Future.value(
_isUserOwner(item)
);
}
bool _isUserOwner(DrivenDistanceDistributedPayment item) {
return item.paidBy == requestingUser.id;
}
bool _isUserInTeam(DrivenDistanceDistributedPayment item) {
return requestingUserTeams.any((e) => e.id == item.id);
}
bool _hasAtLeastOneRoute(DrivenDistanceDistributedPayment item) {
return item.routeIds.isNotEmpty;
}
Future<bool> _areRoutesInSameTeam(DrivenDistanceDistributedPayment item) async {
if(item.routeIds.isEmpty) {
return true;
}
var routes = Stream.fromFutures(item.routeIds.map((e) => getRouteFromId(e)));
var teamToBeComparedTo = await routes.first;
return routes.every((e) => e.teamId == teamToBeComparedTo.teamId);
}
bool _isAmountOk(DrivenDistanceDistributedPayment item) {
return item.amount >= 0;
}
}
import 'dart:async';
import 'package:api/model/payment/equally_distributed.dart';
import 'package:api/model/team.dart';
import 'package:api/model/user.dart';
import 'package:lib/lib.dart';
class EquallyDistributedApiEndpoint extends CheckedDbApiEndpoint<EquallyDistributedPayment, EquallyDistributedPayment> {
final User requestingUser;
final Iterable<Team> requestingUserTeams;
@override
Future<bool> Function(EquallyDistributedPayment) get createItemAllowed => _createItemAllowed;
@override
Future<bool> Function(EquallyDistributedPayment) get getItemAllowed => _getItemAllowed;
@override
Future<bool> Function(EquallyDistributedPayment, EquallyDistributedPayment) get updateItemAllowed => _updateItemAllowed;
@override
Future<bool> Function(EquallyDistributedPayment) get deleteItemAllowed => _deleteItemAllowed;
EquallyDistributedApiEndpoint({
required super.database,
required super.itemFromRequest,
required super.itemToResponse,
required this.requestingUser,
required this.requestingUserTeams,
});
Future<bool> _createItemAllowed(EquallyDistributedPayment item) {
return Future.value(
_isUserOwner(item)
&& _isUserInTeam(item)
&& _isAmountOk(item)
);
}
Future<bool> _getItemAllowed(EquallyDistributedPayment item) {
return Future.value(
_isUserInTeam(item)
);
}
Future<bool> _updateItemAllowed(EquallyDistributedPayment item, EquallyDistributedPayment originalItem) {
return Future.value(
item.id == originalItem.id
&& _isUserOwner(item)
&& _isUserOwner(originalItem)
&& _isUserInTeam(item)
&& _isAmountOk(item)
);
}
Future<bool> _deleteItemAllowed(EquallyDistributedPayment item) {
return Future.value(
_isUserOwner(item)
);
}
bool _isUserOwner(EquallyDistributedPayment item) {
return item.paidBy == requestingUser.id;
}
bool _isUserInTeam(EquallyDistributedPayment item) {
return requestingUserTeams.any((team) => team.id == item.teamId);
}
bool _isAmountOk(EquallyDistributedPayment item) {
return item.amount >= 0;
}
}
import 'package:api/model/payment/user_to_user.dart';
import 'package:api/model/user.dart';
import 'package:lib/lib.dart';
class UserToUserPaymentApiEndpoint extends CheckedDbApiEndpoint<UserToUserPayment, UserToUserPayment> {
final User requestingUser;
@override
Future<bool> Function(UserToUserPayment) get createItemAllowed => _createItemAllowed;
@override
Future<bool> Function(UserToUserPayment) get getItemAllowed => _getItemAllowed;
@override
Future<bool> Function(UserToUserPayment, UserToUserPayment) get updateItemAllowed => _updateItemAllowed;
@override
Future<bool> Function(UserToUserPayment) get deleteItemAllowed => _deleteItemAllowed;
UserToUserPaymentApiEndpoint({
required super.database,
required super.itemFromRequest,
required super.itemToResponse,
required this.requestingUser,
});
Future<bool> _createItemAllowed(UserToUserPayment item) {
return Future.value(
_isUserPayer(item)
&& _isPayerNotPayee(item)
&& _isAmountOk(item)
);
}
Future<bool> _getItemAllowed(UserToUserPayment item) {
return Future.value(
_isUserPayer(item)
|| _isUserPayee(item)
);
}
Future<bool> _updateItemAllowed(UserToUserPayment item, UserToUserPayment originalItem) {
return Future.value(
item.id == originalItem.id
&& _isUserPayer(item)
&& _isUserPayer(originalItem)
&& _isPayerNotPayee(item)
&& _isAmountOk(item)
);
}
Future<bool> _deleteItemAllowed(UserToUserPayment item) {
return Future.value(
_isUserPayer(item)
);
}
bool _isUserPayer(UserToUserPayment item) {
return item.paidBy == requestingUser.id;
}
bool _isUserPayee(UserToUserPayment item) {
return item.paidTo == requestingUser.id;
}
bool _isPayerNotPayee(UserToUserPayment item) {
return item.paidBy != item.paidTo;
}
bool _isAmountOk(UserToUserPayment item) {
return item.amount >= 0;
}
}
...@@ -2,7 +2,11 @@ import 'package:lib/lib.dart'; ...@@ -2,7 +2,11 @@ import 'package:lib/lib.dart';
import 'package:api/model/point.dart'; import 'package:api/model/point.dart';
class PointApiEndpoint extends DbApiEndpoint<Point, Point> { class PointApiEndpoint extends DbApiEndpoint<Point, Point> {
PointApiEndpoint({required super.database, required super.itemFromRequest, required super.itemToResponse}); PointApiEndpoint({
required super.database,
required super.itemFromRequest,
required super.itemToResponse,
});
@override @override
Stream<Point> getAll() { Stream<Point> getAll() {
...@@ -10,12 +14,12 @@ class PointApiEndpoint extends DbApiEndpoint<Point, Point> { ...@@ -10,12 +14,12 @@ class PointApiEndpoint extends DbApiEndpoint<Point, Point> {
} }
@override @override
Future<Map<String, dynamic>> handleDelete(context) { Future<Point> delete(String id) {
throw ApiActionForbiddenException("delete", "point"); throw ApiActionForbiddenException("delete", "point");
} }
@override @override
Future<Map<String, dynamic>> handlePut(context) { Future<Point> update(Point item) {
throw ApiActionForbiddenException("put", "point"); throw ApiActionForbiddenException("put", "point");
} }
} }
import 'package:api/model/requesting_user_details.dart';
import 'package:lib/lib.dart';
import 'package:api/model/route.dart'; import 'package:api/model/route.dart';
import 'package:api/model/team.dart';
import 'package:api/model/user.dart';
import 'package:lib/lib.dart';
class RouteApiEndpoint extends DbApiEndpoint<Route, Route> { class RouteApiEndpoint extends CheckedDbApiEndpoint<Route, Route> {
final RequestingUserDetails requestingUser; final User requestingUser;
RouteApiEndpoint({required super.database, required super.itemFromRequest, required super.itemToResponse, required this.requestingUser}); final Iterable<Team> requestingUserTeams;
@override @override
Future<Route> create(Route item) { Future<bool> Function(Route) get createItemAllowed => _createItemAllowed;
if (!requestingUser.teamIds.contains(item.teamId)){
throw UnauthorizedException();
}
if (requestingUser.userId != item.userId) { @override
throw UnauthorizedException(); Future<bool> Function(Route) get getItemAllowed => _getItemAllowed;
}
return super.create(item); @override
} Future<bool> Function(Route, Route) get updateItemAllowed => _updateItemAllowed;
@override @override
Future<Route> getFromId(String id) async { Future<bool> Function(Route) get deleteItemAllowed => _deleteItemAllowed;
var item = await super.getFromId(id);
if(requestingUser.userId != item.userId) { RouteApiEndpoint({
throw UnauthorizedException(); required super.database,
} required super.itemFromRequest,
required super.itemToResponse,
required this.requestingUser,
required this.requestingUserTeams,
});
return item; Future<bool> _createItemAllowed(Route item) {
return Future.value(
_isUserInTeam(item)
&& _isUserOwner(item)
);
} }
@override Future<bool> _getItemAllowed(Route item) {
Stream<Route> getFromQueries(Iterable<String> queries) async* { return Future.value(
await for(var queryResult in super.getFromQueries(queries)) { _isUserOwner(item)
if (requestingUser.userId == queryResult.userId) { );
yield queryResult;
}
}
} }
@override Future<bool> _updateItemAllowed(Route item, Route originalItem) {
Stream<Route> getAll() async* { return Future.value(
await for(var item in super.getAll()) { item.id == originalItem.id
if(requestingUser.userId == item.userId) { && _isUserInTeam(item)
yield item; && _isUserOwner(item)
} && _isUserOwner(originalItem)
} );
} }
@override Future<bool> _deleteItemAllowed(Route item) {
Future<Route> update(Route item) async { return Future.value(
var routeId = item.id; _isUserOwner(item)
if (routeId == null) { );
throw RequiredArgumentMissing(RequestResponseVariables.idFieldName); }
}
if (requestingUser.userId != item.userId) {
throw UnauthorizedException();
}
var dbItem = await getFromId(item.id!); bool _isUserInTeam(Route item) {
if (requestingUser.userId != dbItem.userId) { return item.teamId != null ? requestingUserTeams.any((e) => e.id == item.teamId) : true;
throw UnauthorizedException(); }
}
return super.update(item); bool _isUserOwner(Route item) {
return item.userId == requestingUser.id;
} }
} }
...@@ -19,10 +19,11 @@ class ScheduleApiEndpoint extends ApiEndpoint { ...@@ -19,10 +19,11 @@ class ScheduleApiEndpoint extends ApiEndpoint {
@override @override
Future<Map<String, dynamic>> handlePost(context) async { Future<Map<String, dynamic>> handlePost(context) async {
if(trigger == "schedule") { if(trigger != "schedule") {
return context.res.send(DateTime.now().toIso8601String()); throw ApiActionForbiddenException("POST", path);
} }
throw ApiActionForbiddenException("POST", path);
return context.res.send(DateTime.now().toIso8601String());
} }
@override @override
......
import 'package:api/model/requesting_user_details.dart';
import 'package:api/model/team.dart'; import 'package:api/model/team.dart';
import 'package:api/service/team_service.dart'; import 'package:api/model/user.dart';
import 'package:lib/lib.dart'; import 'package:lib/lib.dart';
class TeamApiEndpoint extends ApiEndpoint { class TeamApiEndpoint extends ApiEndpoint {
final TeamService teamService; final User requestingUser;
final Stream<Team> Function(User) getTeamsOfUser;
final Map<String, dynamic> Function(Team) itemToResponse; final Map<String, dynamic> Function(Team) itemToResponse;
final RequestingUserDetails requestingUser;
TeamApiEndpoint({required this.teamService, required this.itemToResponse, required this.requestingUser}); TeamApiEndpoint({required this.requestingUser, required this.getTeamsOfUser, required this.itemToResponse});
@override @override
Future<Map<String, dynamic>> handleDelete(context) { Future<Map<String, dynamic>> handleDelete(context) {
...@@ -17,7 +16,7 @@ class TeamApiEndpoint extends ApiEndpoint { ...@@ -17,7 +16,7 @@ class TeamApiEndpoint extends ApiEndpoint {
@override @override
Future<Map<String, dynamic>> handleGet(context) async { Future<Map<String, dynamic>> handleGet(context) async {
var requestingUserTeams = await teamService.getTeamsOfUser(requestingUser.userId).toList(); var requestingUserTeams = await getTeamsOfUser(requestingUser).toList();
return listResponse(context, requestingUserTeams, itemToResponse); return listResponse(context, requestingUserTeams, itemToResponse);
} }
......
import 'dart:convert'; import 'dart:convert';
import 'package:api/model/requesting_user_details.dart'; import 'package:api/model/team.dart';
import 'package:api/service/team_service.dart';
import 'package:api/model/user.dart'; import 'package:api/model/user.dart';
import 'package:lib/lib.dart'; import 'package:lib/lib.dart';
import 'package:api/service/user_service.dart';
class UserApiEndpoint extends ApiEndpoint { class UserApiEndpoint extends ApiEndpoint {
final UserService userService; final User requestingUser;
final TeamService teamService; final Future<User> Function(String) getUserFromId;
final RequestingUserDetails requestingUser; final Stream<Team> Function(User) getTeamsOfUser;
final Map<String, dynamic> Function(User) itemToResponse; final Map<String, dynamic> Function(User) itemToResponse;
UserApiEndpoint({required this.userService, required this.teamService, required this.requestingUser, required this.itemToResponse}); UserApiEndpoint({required this.requestingUser, required this.getUserFromId, required this.getTeamsOfUser, required this.itemToResponse});
@override @override
Future<Map<String, dynamic>> handleDelete(context) { Future<Map<String, dynamic>> handleDelete(context) {
...@@ -23,10 +21,11 @@ class UserApiEndpoint extends ApiEndpoint { ...@@ -23,10 +21,11 @@ class UserApiEndpoint extends ApiEndpoint {
Future<Map<String, dynamic>> handleGet(context) async { Future<Map<String, dynamic>> handleGet(context) async {
var requestedUserId = userIdFromContext(context); var requestedUserId = userIdFromContext(context);
var requestedUser = await userService.getUser(requestedUserId); var requestedUser = await getUserFromId(requestedUserId);
var requestedUserTeamIds = await teamService.getTeamsOfUser(requestedUserId).map((team) => team.teamId).toList(); var requestedUserTeamIds = await getTeamsOfUser(requestedUser).map((e) => e.id).toList();
var requestingUserTeamIds = await getTeamsOfUser(requestingUser).map((e) => e.id).toList();
if(!requestingUser.teamIds.any((teamId) => requestedUserTeamIds.contains(teamId))) { if(!requestedUserTeamIds.any((e) => requestingUserTeamIds.contains(e))) {
throw UnauthorizedException(); throw UnauthorizedException();
} }
......
...@@ -7,7 +7,7 @@ extension EquallyDistributedPaymentRequestResponseConverter on EquallyDistribute ...@@ -7,7 +7,7 @@ extension EquallyDistributedPaymentRequestResponseConverter on EquallyDistribute
return (this as TeamPayment).toResponseData(); return (this as TeamPayment).toResponseData();
} }
static EquallyDistributedPayment fromResponse(Map<String, dynamic> map) { static EquallyDistributedPayment fromRequest(Map<String, dynamic> map) {
var teamPayment = TeamPaymentRequestResponseConverter.fromRequest(map); var teamPayment = TeamPaymentRequestResponseConverter.fromRequest(map);
return EquallyDistributedPayment( return EquallyDistributedPayment(
id: teamPayment.id, id: teamPayment.id,
......
...@@ -4,14 +4,14 @@ import 'package:lib/lib.dart'; ...@@ -4,14 +4,14 @@ import 'package:lib/lib.dart';
extension PaymentRequestResponseConverter on Payment { extension PaymentRequestResponseConverter on Payment {
static const String amountRequestResponseFieldName = "amount"; static const String amountRequestResponseFieldName = "amount";
static const String paidByRequestResponseFieldName = "paidBy"; static const String paidByRequestResponseFieldName = "paidBy";
static const String timeAddedRequestResponseFieldName = "timeAdded"; static const String createdAtRequestResponseFieldName = "timeAdded";
Map<String, dynamic> toResponseData() { Map<String, dynamic> toResponseData() {
return { return {
RequestResponseVariables.idFieldName: id, RequestResponseVariables.idFieldName: id,
amountRequestResponseFieldName: amount, amountRequestResponseFieldName: amount,
paidByRequestResponseFieldName: paidBy, paidByRequestResponseFieldName: paidBy,
timeAddedRequestResponseFieldName: createdAt.toIso8601String(), createdAtRequestResponseFieldName: createdAt.toIso8601String(),
}; };
} }
} }
...@@ -18,7 +18,7 @@ extension TeamPaymentRequestResponseConverter on TeamPayment { ...@@ -18,7 +18,7 @@ extension TeamPaymentRequestResponseConverter on TeamPayment {
id: getOptionalMapItem(RequestResponseVariables.idFieldName, map), id: getOptionalMapItem(RequestResponseVariables.idFieldName, map),
teamId: getRequiredMapItem(teamIdRequestResponseFieldName, map), teamId: getRequiredMapItem(teamIdRequestResponseFieldName, map),
amount: getRequiredMapItem(PaymentRequestResponseConverter.amountRequestResponseFieldName, map), amount: getRequiredMapItem(PaymentRequestResponseConverter.amountRequestResponseFieldName, map),
createdAt: DateTime.parse(getRequiredMapItem(PaymentRequestResponseConverter.timeAddedRequestResponseFieldName, map)), createdAt: DateTime.parse(getRequiredMapItem(PaymentRequestResponseConverter.createdAtRequestResponseFieldName, map)),
paidBy: getRequiredMapItem(PaymentRequestResponseConverter.paidByRequestResponseFieldName, map), paidBy: getRequiredMapItem(PaymentRequestResponseConverter.paidByRequestResponseFieldName, map),
); );
} }
......
import 'package:api/converter/payment/request_response_converter.dart';
import 'package:api/model/payment/payment.dart';
import 'package:api/model/payment/user_to_user.dart';
import 'package:lib/lib.dart';
extension UserToUserPaymentRequestResponseConverter on UserToUserPayment {
static const String paidToRequestResponseFieldName = "paidTo";
Map<String, dynamic> toResponseData() {
return {
paidToRequestResponseFieldName: paidTo,
...(this as Payment).toResponseData()
};
}
static UserToUserPayment fromRequest(Map<String, dynamic> map) {
return UserToUserPayment(
id: getOptionalMapItem(RequestResponseVariables.idFieldName, map),
amount: getRequiredMapItem(PaymentRequestResponseConverter.amountRequestResponseFieldName, map),
createdAt: DateTime.parse(getRequiredMapItem(PaymentRequestResponseConverter.createdAtRequestResponseFieldName, map)),
paidBy: getRequiredMapItem(PaymentRequestResponseConverter.paidByRequestResponseFieldName, map),
paidTo: getRequiredMapItem(paidToRequestResponseFieldName, map)
);
}
}
...@@ -6,8 +6,8 @@ extension TeamRequestResponseConverter on Team { ...@@ -6,8 +6,8 @@ extension TeamRequestResponseConverter on Team {
Map<String, dynamic> toResponseData() { Map<String, dynamic> toResponseData() {
return { return {
teamIdResponseFieldName: teamId, teamIdResponseFieldName: id,
teamNameResponseFieldName: teamName, teamNameResponseFieldName: name,
}; };
} }
} }
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:api/api_endpoint/calendar_event.dart'; import 'package:api/api_endpoint/calendar_event.dart';
import 'package:api/api_endpoint/payment/driven_distance_distributed.dart';
import 'package:api/api_endpoint/payment/equally_distributed.dart';
import 'package:api/api_endpoint/payment/user_to_user.dart';
import 'package:api/converter/payment/user_to_user_payment.dart/request_response_converter.dart';
import 'package:api/database/calendar_event.dart'; import 'package:api/database/calendar_event.dart';
import 'package:api/converter/calendar_event/db_converter.dart'; import 'package:api/converter/calendar_event/db_converter.dart';
import 'package:api/converter/calendar_event/request_response_converter.dart'; import 'package:api/converter/calendar_event/request_response_converter.dart';
...@@ -17,6 +21,8 @@ import 'package:api/converter/route/request_response_converter.dart'; ...@@ -17,6 +21,8 @@ import 'package:api/converter/route/request_response_converter.dart';
import 'package:api/converter/team/request_response_converter.dart'; import 'package:api/converter/team/request_response_converter.dart';
import 'package:api/converter/user/request_response_converter.dart'; import 'package:api/converter/user/request_response_converter.dart';
import 'package:api/api_endpoint/debt.dart'; import 'package:api/api_endpoint/debt.dart';
import 'package:api/model/team.dart';
import 'package:api/model/user.dart';
import 'package:api/service/debt.dart'; import 'package:api/service/debt.dart';
import 'package:api/database/payment/driven_distance_distributed.dart'; import 'package:api/database/payment/driven_distance_distributed.dart';
import 'package:api/database/payment/equally_distributed.dart'; import 'package:api/database/payment/equally_distributed.dart';
...@@ -24,8 +30,8 @@ import 'package:api/database/payment/user_to_user.dart'; ...@@ -24,8 +30,8 @@ import 'package:api/database/payment/user_to_user.dart';
import 'package:api/model/payment/driven_distance_distributed.dart'; import 'package:api/model/payment/driven_distance_distributed.dart';
import 'package:api/model/payment/equally_distributed.dart'; import 'package:api/model/payment/equally_distributed.dart';
import 'package:api/model/payment/user_to_user.dart'; import 'package:api/model/payment/user_to_user.dart';
import 'package:api/model/requesting_user_details.dart';
import 'package:api/api_endpoint/team.dart'; import 'package:api/api_endpoint/team.dart';
import 'package:api/service/membership_service.dart';
import 'package:api/service/team_service.dart'; import 'package:api/service/team_service.dart';
import 'package:lib/lib.dart'; import 'package:lib/lib.dart';
import 'package:api/api_endpoint/point.dart'; import 'package:api/api_endpoint/point.dart';
...@@ -44,6 +50,7 @@ const String teamApiEndpoint = "/team"; ...@@ -44,6 +50,7 @@ const String teamApiEndpoint = "/team";
const String userApiPath = "/user"; const String userApiPath = "/user";
const String drivenDistanceDistributedPaymentApiEndpoint = "/payment/team/drivendistance"; const String drivenDistanceDistributedPaymentApiEndpoint = "/payment/team/drivendistance";
const String equallyDistributedPaymentApiEndpoint = "/payment/team/equal"; const String equallyDistributedPaymentApiEndpoint = "/payment/team/equal";
const String userToUserPaymentApiEndpoint = "/payment/user";
const String debtApiEndpoint = "/debt"; const String debtApiEndpoint = "/debt";
Future<dynamic> main(final context) async { Future<dynamic> main(final context) async {
...@@ -103,13 +110,15 @@ Future<dynamic> main(final context) async { ...@@ -103,13 +110,15 @@ Future<dynamic> main(final context) async {
); );
var teamService = TeamService(host: host, projectId: projectId, apiKey: apiKey); var teamService = TeamService(host: host, projectId: projectId, apiKey: apiKey);
var userService = UserService(host: host, projectId: projectId, apiKey: apiKey);
var membershipService = MembershipService(host: host, projectId: projectId, apiKey: apiKey, teamService: teamService, userService: userService);
var debtService = DebtService( var debtService = DebtService(
getMembershipsByTeamId: membershipService.getTeamMemberships,
getRouteById: routeDatabase.get, getRouteById: routeDatabase.get,
getTeamById: teamService.getTeam,
getUserToUserPayments: (userId) => getUserToUserPayments(userId, userToUserPaymentDatabase), getUserToUserPayments: (userId) => getUserToUserPayments(userId, userToUserPaymentDatabase),
getEquallyDistributedPayments: (userId) => getEquallyDistributedPayments(userId, teamService, equallyDistributedPaymentDatabase), getEquallyDistributedPayments: (userId) => getEquallyDistributedPayments(userId, membershipService, equallyDistributedPaymentDatabase),
getDrivenDistanceDistributedPayments: (userId) => getDrivenDistanceDistributedPayments(userId, teamService, drivenDistanceDistributedPaymentDatabase), getDrivenDistanceDistributedPayments: (userId) => getDrivenDistanceDistributedPayments(userId, membershipService, drivenDistanceDistributedPaymentDatabase),
); );
ApiEndpoint apiEndpoint; ApiEndpoint apiEndpoint;
...@@ -127,69 +136,92 @@ Future<dynamic> main(final context) async { ...@@ -127,69 +136,92 @@ Future<dynamic> main(final context) async {
break; break;
case routeApiPath: case routeApiPath:
var requestingUser = await getRequestingUser(context, teamService); var requestingUser = await getRequestingUser(context, userService);
var requestingUserTeams = await getUserTeams(requestingUser.id, membershipService).toList();
apiEndpoint = RouteApiEndpoint( apiEndpoint = RouteApiEndpoint(
database: routeDatabase, database: routeDatabase,
requestingUser: requestingUser, requestingUser: requestingUser,
itemFromRequest: (m) => RouteRequestResponseConverter.fromRequest(m, requestingUser.userId), requestingUserTeams: requestingUserTeams,
itemFromRequest: (m) => RouteRequestResponseConverter.fromRequest(m, requestingUser.id),
itemToResponse: (r) => r.toResponseData(), itemToResponse: (r) => r.toResponseData(),
); );
break; break;
case teamApiEndpoint: case teamApiEndpoint:
var requestingUser = await getRequestingUser(context, teamService); var requestingUser = await getRequestingUser(context, userService);
apiEndpoint = TeamApiEndpoint( apiEndpoint = TeamApiEndpoint(
teamService: teamService,
requestingUser: requestingUser, requestingUser: requestingUser,
getTeamsOfUser: (user) => getUserTeams(user.id, membershipService),
itemToResponse: (e) => e.toResponseData(), itemToResponse: (e) => e.toResponseData(),
); );
break; break;
case calendarEventApiPath: case calendarEventApiPath:
var requestingUser = await getRequestingUser(context, teamService); var requestingUser = await getRequestingUser(context, userService);
var requestingUserTeams = await getUserTeams(requestingUser.id, membershipService).toList();
apiEndpoint = CalendarEventApiEndpoint( apiEndpoint = CalendarEventApiEndpoint(
database: calendarEventDatabase, database: calendarEventDatabase,
itemFromRequest: (m) => CalendarEventRequestResponseConverter.fromRequest(m, requestingUser.userId), itemFromRequest: (m) => CalendarEventRequestResponseConverter.fromRequest(m, requestingUser.id),
itemToResponse: (ce) => ce.toResponseData(), itemToResponse: (ce) => ce.toResponseData(),
requestingUser: requestingUser requestingUser: requestingUser,
requestingUserTeams: requestingUserTeams,
); );
break; break;
case userApiPath: case userApiPath:
var requestingUser = await getRequestingUser(context, teamService); var requestingUser = await getRequestingUser(context, userService);
apiEndpoint = UserApiEndpoint( apiEndpoint = UserApiEndpoint(
userService: UserService(host: host, projectId: projectId, apiKey: apiKey),
teamService: teamService,
requestingUser: requestingUser, requestingUser: requestingUser,
getTeamsOfUser: (user) => getUserTeams(user.id, membershipService),
getUserFromId: userService.getUser,
itemToResponse: (e) => e.toResponseData(), itemToResponse: (e) => e.toResponseData(),
); );
break; break;
case drivenDistanceDistributedPaymentApiEndpoint: case drivenDistanceDistributedPaymentApiEndpoint:
apiEndpoint = DbApiEndpoint<DrivenDistanceDistributedPayment, DrivenDistanceDistributedPayment>( // TODO var requestingUser = await getRequestingUser(context, userService);
apiEndpoint = DrivenDistanceDistributedPaymentApiEndpoint(
database: drivenDistanceDistributedPaymentDatabase, database: drivenDistanceDistributedPaymentDatabase,
itemFromRequest: DrivenDistanceDistributedPaymentRequestResponseConverter.fromRequest, itemFromRequest: DrivenDistanceDistributedPaymentRequestResponseConverter.fromRequest,
itemToResponse: (e) => e.toResponseData(), itemToResponse: (e) => e.toResponseData(),
requestingUser: requestingUser,
requestingUserTeams: await getUserTeams(requestingUser.id, membershipService).toList(),
getRouteFromId: routeDatabase.get
); );
break; break;
case equallyDistributedPaymentApiEndpoint: case equallyDistributedPaymentApiEndpoint:
apiEndpoint = DbApiEndpoint<EquallyDistributedPayment, EquallyDistributedPayment>( // TODO var requestingUser = await getRequestingUser(context, userService);
apiEndpoint = EquallyDistributedApiEndpoint(
database: equallyDistributedPaymentDatabase, database: equallyDistributedPaymentDatabase,
itemFromRequest: EquallyDistributedPaymentRequestResponseConverter.fromResponse, requestingUser: requestingUser,
requestingUserTeams: await getUserTeams(requestingUser.id, membershipService).toList(),
itemFromRequest: EquallyDistributedPaymentRequestResponseConverter.fromRequest,
itemToResponse: (e) => e.toResponseData(), itemToResponse: (e) => e.toResponseData(),
); );
break; break;
case userToUserPaymentApiEndpoint:
var requestingUser = await getRequestingUser(context, userService);
apiEndpoint = UserToUserPaymentApiEndpoint(
database: userToUserPaymentDatabase,
requestingUser: requestingUser,
itemFromRequest: UserToUserPaymentRequestResponseConverter.fromRequest,
itemToResponse: (e) => e.toResponseData(),
);
break;
case debtApiEndpoint: case debtApiEndpoint:
var requestingUser = await getRequestingUser(context, teamService); var requestingUser = await getRequestingUser(context, userService);
apiEndpoint = DebtApiEndpoint( apiEndpoint = DebtApiEndpoint(
debtService: debtService, debtService: debtService,
itemToResponse: (e) => e.toResponseData(), itemToResponse: (e) => e.toResponseData(),
requestingUser: requestingUser, requestingUser: requestingUser,
); );
break;
default: default:
throw HttpException("Path $requestPath not found", uri: Uri.parse(context.req.url)); throw HttpException("Path $requestPath not found", uri: Uri.parse(context.req.url));
...@@ -199,24 +231,25 @@ Future<dynamic> main(final context) async { ...@@ -199,24 +231,25 @@ Future<dynamic> main(final context) async {
return requestHandler.handleRequest(context); return requestHandler.handleRequest(context);
} }
Future<RequestingUserDetails> getRequestingUser(final context, TeamService teamService) async { Future<User> getRequestingUser(final context, UserService userService) async {
final userId = AppwriteVariables.userId(context); final userId = AppwriteVariables.userId(context);
return RequestingUserDetails( return userService.getUser(userId);
userId: userId, }
teamIds: await teamService.getTeamsOfUser(userId).map((e) => e.teamId).toList(),
); Stream<Team> getUserTeams(String userId, MembershipService membershipService) {
return membershipService.getUserMemberships(userId).map((e) => e.team);
} }
Stream<UserToUserPayment> getUserToUserPayments(String userId, UserToUserPaymentDatabase userToUserPaymentDatabase) { Stream<UserToUserPayment> getUserToUserPayments(String userId, UserToUserPaymentDatabase userToUserPaymentDatabase) {
return userToUserPaymentDatabase.getAll().where((e) => e.paidBy == userId || e.paidTo == userId); return userToUserPaymentDatabase.getAll().where((e) => e.paidBy == userId || e.paidTo == userId);
} }
Stream<EquallyDistributedPayment> getEquallyDistributedPayments(String userId, TeamService teamService, EquallyDistributedPaymentDatabase equallyDistributedPaymentDatabase) async* { Stream<EquallyDistributedPayment> getEquallyDistributedPayments(String userId, MembershipService membershipService, EquallyDistributedPaymentDatabase equallyDistributedPaymentDatabase) async* {
var userTeamIds = await teamService.getTeamsOfUser(userId).map((e) => e.teamId).toList(); var userTeamIds = await membershipService.getUserMemberships(userId).map((e) => e.team.id).toList();
yield* equallyDistributedPaymentDatabase.getAll().where((e) => userTeamIds.contains(e.teamId)); // Would be nice with queries, but appwrite does not support nested queries yield* equallyDistributedPaymentDatabase.getAll().where((e) => userTeamIds.contains(e.teamId)); // Would be nice with queries, but appwrite does not support nested queries
} }
Stream<DrivenDistanceDistributedPayment> getDrivenDistanceDistributedPayments(String userId, TeamService teamService, DrivenDistanceDistributedPaymentDatabase drivenDistanceDistributedPaymentDatabase) async* { Stream<DrivenDistanceDistributedPayment> getDrivenDistanceDistributedPayments(String userId, MembershipService membershipService, DrivenDistanceDistributedPaymentDatabase drivenDistanceDistributedPaymentDatabase) async* {
var userTeamIds = await teamService.getTeamsOfUser(userId).map((e) => e.teamId).toList(); var userTeamIds = await membershipService.getUserMemberships(userId).map((e) => e.team.id).toList();
yield* drivenDistanceDistributedPaymentDatabase.getAll().where((e) => userTeamIds.contains(e.teamId)); // Would be nice with queries, but appwrite does not support nested queries yield* drivenDistanceDistributedPaymentDatabase.getAll().where((e) => userTeamIds.contains(e.teamId)); // Would be nice with queries, but appwrite does not support nested queries
} }
class AppwriteUser {
final String id;
final String email;
final String name;
final bool isEnabled;
AppwriteUser({required this.id, required this.email, required this.name, required this.isEnabled});
}
import 'package:api/model/appwrite_user.dart'; import 'package:api/model/team.dart';
import 'package:api/model/user.dart';
class Membership { class Membership {
final AppwriteUser user; final User user;
final Team team;
final DateTime joinedAt; final DateTime joinedAt;
Membership({required this.user, required this.joinedAt}); Membership({required this.user, required this.team, required this.joinedAt});
} }
class RequestingUserDetails {
final String userId;
final Iterable<String> teamIds;
RequestingUserDetails({required this.userId, required this.teamIds});
}
import 'package:api/model/membership.dart';
class Team { class Team {
final String teamId; final String id;
final String teamName; final String name;
final Iterable<Membership> memberships;
Team({required this.teamId, required this.teamName, required this.memberships}); Team({required this.id, required this.name});
} }