├── .DS_Store ├── .vscode └── launch.json ├── README.md ├── dart_frog.png └── tasklist_backend ├── .gitignore ├── README.md ├── analysis_options.yaml ├── config.json ├── dart_frog.png ├── lib ├── config.dart ├── hash_extension.dart └── repository │ ├── items │ ├── item_Repository.dart │ └── item_Repository.g.dart │ ├── lists │ ├── list_Repository.dart │ └── list_Repository.g.dart │ ├── session │ └── session_repository.dart │ └── user │ └── user_repository.dart ├── public ├── images │ └── coding.jpg └── tasklist │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── analysis_options.yaml │ ├── pubspec.yaml │ └── web │ ├── index.html │ ├── main.dart │ └── styles.css ├── publicScreenshot 2023-01-09 at 06.06.03.png ├── pubspec.yaml └── routes ├── _middleware.dart ├── api └── restapi │ ├── _middleware.dart │ └── index.dart ├── authentication ├── basic │ ├── [id].dart │ ├── _middleware.dart │ └── index.dart └── bearer │ ├── [id].dart │ ├── _middleware.dart │ └── index.dart ├── cache └── redis │ ├── _middleware.dart │ └── index.dart ├── db ├── fbase │ ├── [id].dart │ ├── _middleware.dart │ └── index.dart ├── mongodb │ ├── [id].dart │ ├── _middleware.dart │ └── index.dart └── postgresql │ ├── [id].dart │ ├── _middleware.dart │ └── index.dart ├── files ├── _middleware.dart └── index.dart ├── index.dart ├── items ├── [id].dart └── index.dart ├── lists ├── [id].dart └── index.dart └── ws.dart /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mobterest/dart_frog_tutorial/54318868ab8e844f2fffe48330d33edf279077f1/.DS_Store -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "tasklist_backend", 9 | "cwd": "tasklist_backend", 10 | "request": "launch", 11 | "type": "dart" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dart Frog Tutorial 2 | 3 | ## Introduction 4 | 5 | Built with [Dart](https://dart.dev/) :star2: 6 | 7 | [![Watch the Full Tutorial](dart_frog.png)](https://www.youtube.com/watch?v=DlFYxNXERyI&list=PLKKf8l1ne4_h9ttT_ihJ7xelHU1-o3w90) 8 | -------------------------------------------------------------------------------- /dart_frog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mobterest/dart_frog_tutorial/54318868ab8e844f2fffe48330d33edf279077f1/dart_frog.png -------------------------------------------------------------------------------- /tasklist_backend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by the Operating System 4 | .DS_Store 5 | 6 | # Files and directories created by pub 7 | .dart_tool/ 8 | .packages 9 | pubspec.lock 10 | 11 | # Files and directories created by dart_frog 12 | build/ 13 | .dart_frog 14 | 15 | # Test related files 16 | coverage/ -------------------------------------------------------------------------------- /tasklist_backend/README.md: -------------------------------------------------------------------------------- 1 | # Dart Frog Tutorial 2 | 3 | ## Introduction 4 | 5 | Built with [Dart](https://dart.dev/) :star2: 6 | 7 | [![Watch the Full Tutorial](dart_frog.png)](https://www.youtube.com/watch?v=DlFYxNXERyI&list=PLKKf8l1ne4_h9ttT_ihJ7xelHU1-o3w90) 8 | -------------------------------------------------------------------------------- /tasklist_backend/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.5.0.0.yaml 2 | analyzer: 3 | exclude: 4 | - build/** 5 | linter: 6 | rules: 7 | file_names: false 8 | -------------------------------------------------------------------------------- /tasklist_backend/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "redis": { 3 | "host": "localhost", 4 | "port": 8091, 5 | "username": "default", 6 | "password": "", 7 | "auth_command": "AUTH" 8 | }, 9 | "restapi": { 10 | "url": "https://low-carb-recipes.p.rapidapi.com/random", 11 | "key": "", 12 | "host": "low-carb-recipes.p.rapidapi.com" 13 | }, 14 | "openai": { 15 | "key": "" 16 | }, 17 | "files":{ 18 | "public_path": "/public/" 19 | } 20 | } -------------------------------------------------------------------------------- /tasklist_backend/dart_frog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mobterest/dart_frog_tutorial/54318868ab8e844f2fffe48330d33edf279077f1/tasklist_backend/dart_frog.png -------------------------------------------------------------------------------- /tasklist_backend/lib/config.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | /// Configuration class 5 | class Configuration { 6 | /// Read configurations from config.json 7 | Future> getRedisConfigurations() async { 8 | final configFile = File('./config.json'); 9 | final jsonString = await configFile.readAsString(); 10 | final map = jsonDecode(jsonString) as Map; 11 | final redisConfig = map['redis'] as Map; 12 | return redisConfig; 13 | } 14 | 15 | /// Read configurations from config.json 16 | Future> getAPIConfigurations() async { 17 | final configFile = File('./config.json'); 18 | final jsonString = await configFile.readAsString(); 19 | final map = jsonDecode(jsonString) as Map; 20 | final config = map['restapi'] as Map; 21 | return config; 22 | } 23 | 24 | /// Read configurations from config.json 25 | Future> getFileConfigurations() async { 26 | final configFile = File('./config.json'); 27 | final jsonString = await configFile.readAsString(); 28 | final map = jsonDecode(jsonString) as Map; 29 | final config = map['files'] as Map; 30 | return config; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tasklist_backend/lib/hash_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:crypto/crypto.dart'; 4 | 5 | 6 | /// Add hash functionality to our String id 7 | extension HashStringExtension on String { 8 | 9 | /// Returns the SHA256 hash of this [String] 10 | String get hashValue { 11 | return sha256.convert(utf8.encode(this)).toString(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tasklist_backend/lib/repository/items/item_Repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:meta/meta.dart'; 4 | import 'package:tasklist_backend/hash_extension.dart'; 5 | 6 | part 'item_Repository.g.dart'; 7 | 8 | @visibleForTesting 9 | 10 | /// Data source - in-memory cache 11 | Map itemtDb = {}; 12 | 13 | @JsonSerializable() 14 | 15 | /// TaskList class 16 | class TaskItem extends Equatable { 17 | /// Constructor 18 | const TaskItem({ 19 | required this.id, 20 | required this.listid, 21 | required this.name, 22 | required this.description, 23 | required this.status, 24 | }); 25 | 26 | /// deserialization 27 | factory TaskItem.fromJson(Map json) => 28 | _$TaskItemFromJson(json); 29 | 30 | /// copyWith method 31 | TaskItem copyWith( 32 | {String? id, 33 | String? listid, 34 | String? name, 35 | String? description, 36 | bool? status}) { 37 | return TaskItem( 38 | id: id ?? this.id, 39 | listid: listid ?? this.listid, 40 | name: name ?? this.name, 41 | description: description ?? this.description, 42 | status: status ?? this.status, 43 | ); 44 | } 45 | 46 | /// Item's id 47 | final String id; 48 | 49 | /// List id of where the item belongs 50 | final String listid; 51 | 52 | /// Item's name 53 | final String name; 54 | 55 | /// Item's description 56 | final String description; 57 | 58 | /// Item's status 59 | final bool status; 60 | 61 | /// Serialization 62 | Map toJson() => _$TaskItemToJson(this); 63 | 64 | @override 65 | List get props => [id, name]; 66 | } 67 | 68 | /// Repository class for TaskItem 69 | /// 70 | class TaskItemRepository { 71 | /// Check in the internal data source for an item with the given [id 72 | Future itemById(String id) async { 73 | return itemtDb[id]; 74 | } 75 | 76 | /// Get all the items from the data source 77 | Map getAllItems() { 78 | final formattedItems = {}; 79 | 80 | if (itemtDb.isNotEmpty) { 81 | itemtDb.forEach((key, value) { 82 | formattedItems[key] = value.toJson(); 83 | }); 84 | } 85 | 86 | return formattedItems; 87 | } 88 | 89 | /// Get items by list id 90 | Map getItemsByList(String listid) { 91 | final formattedItems = {}; 92 | if (itemtDb.isNotEmpty) { 93 | itemtDb.forEach((key, value) { 94 | if (value.listid == listid) { 95 | formattedItems[key] = value.toJson(); 96 | } 97 | }); 98 | } 99 | return formattedItems; 100 | } 101 | 102 | /// Create a new item with a given information 103 | String createItem({ 104 | required String name, 105 | required String listid, 106 | required String description, 107 | required bool status, 108 | }) { 109 | /// dynamically generates the id 110 | final id = name.hashValue; 111 | 112 | /// create our new TaskiTEM object and pass ALL THE parameters 113 | final item = TaskItem( 114 | id: id, 115 | name: name, 116 | listid: listid, 117 | description: description, 118 | status: status); 119 | 120 | /// add a new Tasklist object to our data source 121 | itemtDb[id] = item; 122 | 123 | return id; 124 | } 125 | 126 | /// Deletes the Taskitem object with the given [id] 127 | void deleteItem(String id) { 128 | itemtDb.remove(id); 129 | } 130 | 131 | /// Update operation 132 | Future updateItem({ 133 | required String id, 134 | required String name, 135 | required String listid, 136 | required String description, 137 | required bool status, 138 | }) async { 139 | final currentitem = itemtDb[id]; 140 | 141 | if (currentitem == null) { 142 | return Future.error(Exception('Item not found')); 143 | } 144 | 145 | itemtDb[id] = TaskItem( 146 | id: id, 147 | name: name, 148 | listid: listid, 149 | description: description, 150 | status: status); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /tasklist_backend/lib/repository/items/item_Repository.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'item_Repository.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TaskItem _$TaskItemFromJson(Map json) => TaskItem( 10 | id: json['id'] as String, 11 | listid: json['listid'] as String, 12 | name: json['name'] as String, 13 | description: json['description'] as String, 14 | status: json['status'] as bool, 15 | ); 16 | 17 | Map _$TaskItemToJson(TaskItem instance) => { 18 | 'id': instance.id, 19 | 'listid': instance.listid, 20 | 'name': instance.name, 21 | 'description': instance.description, 22 | 'status': instance.status, 23 | }; 24 | -------------------------------------------------------------------------------- /tasklist_backend/lib/repository/lists/list_Repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:json_annotation/json_annotation.dart'; 3 | import 'package:meta/meta.dart'; 4 | import 'package:tasklist_backend/hash_extension.dart'; 5 | 6 | part 'list_Repository.g.dart'; 7 | 8 | @visibleForTesting 9 | 10 | /// Data source - in-memory cache 11 | Map listDb = {}; 12 | 13 | @JsonSerializable() 14 | 15 | /// TaskList class 16 | class TaskList extends Equatable { 17 | /// Constructor 18 | const TaskList({required this.id, required this.name}); 19 | 20 | /// deserialization 21 | factory TaskList.fromJson(Map json) => 22 | _$TaskListFromJson(json); 23 | 24 | /// copyWith method 25 | TaskList copyWith({ 26 | String? id, 27 | String? name, 28 | }) { 29 | return TaskList(id: id ?? this.id, name: name ?? this.name); 30 | } 31 | 32 | /// List's id 33 | final String id; 34 | 35 | /// List's name 36 | final String name; 37 | 38 | /// Serialization 39 | Map toJson() => _$TaskListToJson(this); 40 | 41 | @override 42 | List get props => [id, name]; 43 | } 44 | 45 | /// Repository class for TaskList 46 | /// 47 | class TaskListRepository { 48 | /// Check in the internal data source for a list with the given [id 49 | Future listById(String id) async { 50 | return listDb[id]; 51 | } 52 | 53 | /// Get all the lists from the data source 54 | Map getAllLists() { 55 | final formattedLists = {}; 56 | 57 | if (listDb.isNotEmpty) { 58 | listDb.forEach((key, value) { 59 | formattedLists[key] = value.toJson(); 60 | }); 61 | } 62 | 63 | return formattedLists; 64 | } 65 | 66 | /// Create a new list with a given [name] 67 | String createList({required String name}) { 68 | /// dynamically generates the id 69 | final id = name.hashValue; 70 | 71 | /// create our new TaskList object and pass our two parameters 72 | final list = TaskList(id: id, name: name); 73 | 74 | /// add a new Tasklist object to our data source 75 | listDb[id] = list; 76 | 77 | return id; 78 | } 79 | 80 | /// Deletes the Tasklist object with the given [id] 81 | void deleteList(String id) { 82 | listDb.remove(id); 83 | } 84 | 85 | /// Update operation 86 | Future updateList({required String id, required String name}) async { 87 | final currentlist = listDb[id]; 88 | 89 | if (currentlist == null) { 90 | return Future.error(Exception('List not found')); 91 | } 92 | 93 | listDb[id] = TaskList(id: id, name: name); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tasklist_backend/lib/repository/lists/list_Repository.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'list_Repository.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | TaskList _$TaskListFromJson(Map json) => TaskList( 10 | id: json['id'] as String, 11 | name: json['name'] as String, 12 | ); 13 | 14 | Map _$TaskListToJson(TaskList instance) => { 15 | 'id': instance.id, 16 | 'name': instance.name, 17 | }; 18 | -------------------------------------------------------------------------------- /tasklist_backend/lib/repository/session/session_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:meta/meta.dart'; 3 | import 'package:tasklist_backend/hash_extension.dart'; 4 | 5 | @visibleForTesting 6 | /// in memory database 7 | Map sessionDb = {}; 8 | 9 | ///A Session class 10 | class Session extends Equatable { 11 | /// constructor 12 | const Session({ 13 | required this.token, 14 | required this.userId, 15 | required this.expiryDate, 16 | required this.createdAt, 17 | }); 18 | 19 | /// The session token 20 | final String token; 21 | 22 | /// User's ID 23 | final String userId; 24 | 25 | /// When it will expire 26 | final DateTime expiryDate; 27 | 28 | /// When it was created 29 | final DateTime createdAt; 30 | 31 | @override 32 | List get props => [token, userId, expiryDate, createdAt]; 33 | } 34 | 35 | /// Session Repository 36 | class SessionRepository { 37 | /// Create session 38 | Session createSession(String userId) { 39 | final session = Session( 40 | token: generateToken(userId), 41 | userId: userId, 42 | expiryDate: DateTime.now().add(const Duration(hours: 24)), 43 | createdAt: DateTime.now()); 44 | 45 | sessionDb[session.token] = session; 46 | return session; 47 | } 48 | 49 | /// generate token 50 | String generateToken(String userId) { 51 | return '${userId}_${DateTime.now().toIso8601String()}'.hashValue; 52 | } 53 | 54 | /// Search a session of a particular token 55 | Session? sessionFromToken(String token) { 56 | final session = sessionDb[token]; 57 | 58 | if (session != null && session.expiryDate.isAfter(DateTime.now())) { 59 | return session; 60 | } 61 | return null; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tasklist_backend/lib/repository/user/user_repository.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:meta/meta.dart'; 3 | import 'package:tasklist_backend/hash_extension.dart'; 4 | 5 | @visibleForTesting 6 | 7 | /// IN MEMORY CACHE 8 | Map userDb = {}; 9 | 10 | /// User's class 11 | class User extends Equatable { 12 | /// Constructor 13 | const User({ 14 | required this.id, 15 | required this.name, 16 | required this.username, 17 | required this.password, 18 | }); 19 | 20 | /// User's id 21 | final String id; 22 | 23 | /// User's name 24 | final String name; 25 | 26 | /// User's username 27 | final String username; 28 | 29 | /// User's password 30 | final String password; 31 | 32 | @override 33 | List get props => [id, name, username, password]; 34 | } 35 | 36 | /// User's Repository 37 | class UserRepository { 38 | /// Checks in the database for a user with the provided username and password 39 | Future userFromCredentials(String username, String password) async { 40 | final hashedPassword = password.hashValue; 41 | 42 | final users = userDb.values.where( 43 | (user) => user.username == username && user.password == hashedPassword, 44 | ); 45 | 46 | if (users.isNotEmpty) { 47 | return users.first; 48 | } 49 | 50 | return null; 51 | } 52 | 53 | /// search for a user by id 54 | Future userFromId(String id) async { 55 | return userDb[id]; 56 | } 57 | 58 | /// Creates a new user 59 | Future createUser( 60 | {required String name, 61 | required String username, 62 | required String password}) { 63 | final id = username.hashValue; 64 | 65 | final user = User( 66 | id: id, 67 | username: username, 68 | password: password.hashValue, 69 | name: name, 70 | ); 71 | 72 | userDb[id] = user; 73 | 74 | return Future.value(id); 75 | } 76 | 77 | /// Delete a user 78 | void deleteUser(String id) { 79 | userDb.remove(id); 80 | } 81 | 82 | /// Update user 83 | Future updateUser({ 84 | required String id, 85 | required String? name, 86 | required String? username, 87 | required String? password, 88 | }) async { 89 | final currentUser = userDb[id]; 90 | 91 | if (currentUser == null) { 92 | return Future.error(Exception('User not found')); 93 | } 94 | 95 | if (password != null) { 96 | password = password.hashValue; 97 | } 98 | 99 | final user = User( 100 | id: id, 101 | name: name ?? currentUser.name, 102 | username: username ?? currentUser.username, 103 | password: password ?? currentUser.password, 104 | ); 105 | 106 | userDb[id] = user; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /tasklist_backend/public/images/coding.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mobterest/dart_frog_tutorial/54318868ab8e844f2fffe48330d33edf279077f1/tasklist_backend/public/images/coding.jpg -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/.gitignore: -------------------------------------------------------------------------------- 1 | # https://dart.dev/guides/libraries/private-files 2 | # Created by `dart pub` 3 | .dart_tool/ 4 | -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - Initial version. 4 | -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/README.md: -------------------------------------------------------------------------------- 1 | An absolute bare-bones web app. 2 | -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the static analysis results for your project (errors, 2 | # warnings, and lints). 3 | # 4 | # This enables the 'recommended' set of lints from `package:lints`. 5 | # This set helps identify many issues that may lead to problems when running 6 | # or consuming Dart code, and enforces writing Dart using a single, idiomatic 7 | # style and format. 8 | # 9 | # If you want a smaller set of lints you can change this to specify 10 | # 'package:lints/core.yaml'. These are just the most critical lints 11 | # (the recommended set includes the core lints). 12 | # The core lints are also what is used by pub.dev for scoring packages. 13 | 14 | include: package:lints/recommended.yaml 15 | 16 | # Uncomment the following section to specify additional rules. 17 | 18 | # linter: 19 | # rules: 20 | # - camel_case_types 21 | 22 | # analyzer: 23 | # exclude: 24 | # - path/to/excluded/files/** 25 | 26 | # For more information about the core and recommended set of lints, see 27 | # https://dart.dev/go/core-lints 28 | 29 | # For additional information about configuring this file, see 30 | # https://dart.dev/guides/language/analysis-options 31 | -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: tasklist 2 | description: An absolute bare-bones web app. 3 | version: 1.0.0 4 | # repository: https://github.com/my_org/my_repo 5 | 6 | environment: 7 | sdk: ^3.0.6 8 | 9 | # Add regular dependencies here. 10 | dependencies: 11 | # path: ^1.8.0 12 | 13 | dev_dependencies: 14 | build_runner: ^2.4.0 15 | build_web_compilers: ^4.0.0 16 | lints: ^2.0.0 17 | -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | tasklist 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/web/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:html'; 2 | 3 | void main() { 4 | querySelector('#output')?.text = 'Your Dart app is running.'; 5 | } 6 | -------------------------------------------------------------------------------- /tasklist_backend/public/tasklist/web/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Roboto); 2 | 3 | html, body { 4 | width: 100%; 5 | height: 100%; 6 | margin: 0; 7 | padding: 0; 8 | font-family: 'Roboto', sans-serif; 9 | } 10 | 11 | #output { 12 | padding: 20px; 13 | text-align: center; 14 | } 15 | -------------------------------------------------------------------------------- /tasklist_backend/publicScreenshot 2023-01-09 at 06.06.03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mobterest/dart_frog_tutorial/54318868ab8e844f2fffe48330d33edf279077f1/tasklist_backend/publicScreenshot 2023-01-09 at 06.06.03.png -------------------------------------------------------------------------------- /tasklist_backend/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: tasklist_backend 2 | description: An new Dart Frog application 3 | version: 1.0.0+1 4 | publish_to: none 5 | 6 | environment: 7 | sdk: ">=3.0.0 <4.0.0" 8 | 9 | dependencies: 10 | build_runner: ^2.4.6 11 | crypto: ^3.0.3 12 | dart_frog: ^1.0.0 13 | dart_frog_auth: ^1.1.0 14 | dart_frog_web_socket: ^1.0.0 15 | equatable: ^2.0.5 16 | firedart: ^0.9.7 17 | http: ^1.1.0 18 | json_annotation: ^4.8.1 19 | json_serializable: ^6.7.1 20 | meta: ^1.10.0 21 | mongo_dart: ^0.9.1 22 | postgres: ^2.6.2 23 | redis: ^3.1.0 24 | shelf_cors_headers: ^0.1.5 25 | 26 | dev_dependencies: 27 | mocktail: ^1.0.0 28 | test: ^1.19.2 29 | very_good_analysis: ^5.0.0 30 | -------------------------------------------------------------------------------- /tasklist_backend/routes/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:shelf_cors_headers/shelf_cors_headers.dart' as shelf; 3 | import 'package:tasklist_backend/repository/items/item_Repository.dart'; 4 | import 'package:tasklist_backend/repository/lists/list_Repository.dart'; 5 | 6 | Handler middleware(Handler handler) { 7 | return handler 8 | .use(requestLogger()) 9 | .use(provider((context) => TaskListRepository())) 10 | .use(provider((context) => TaskItemRepository())) 11 | .use( 12 | fromShelfMiddleware( 13 | shelf.corsHeaders( 14 | headers: { 15 | shelf.ACCESS_CONTROL_ALLOW_METHODS: 'GET POST DELETE PATCH' 16 | }, 17 | ), 18 | ), 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /tasklist_backend/routes/api/restapi/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | 3 | Handler middleware(Handler handler) { 4 | return handler.use(requestLogger()); 5 | } 6 | -------------------------------------------------------------------------------- /tasklist_backend/routes/api/restapi/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:http/http.dart' as http; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.get => _getRecipes(context), 9 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 10 | }; 11 | } 12 | 13 | Future _getRecipes(RequestContext context) async { 14 | final response = await http.get( 15 | Uri.parse('https://low-carb-recipes.p.rapidapi.com/random'), 16 | headers: { 17 | 'X-RapidAPI-Key': 'b8849a6c88msha9a7ef62f3ef62ap1d9327jsn03d96a53bc74', 18 | 'X-RapidAPI-Host': 'low-carb-recipes.p.rapidapi.com' 19 | }, 20 | ); 21 | 22 | if (response.statusCode == 200) { 23 | return Response.json(body: response.body); 24 | } else { 25 | return Response(statusCode: HttpStatus.badRequest); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tasklist_backend/routes/authentication/basic/[id].dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/user/user_repository.dart'; 5 | 6 | Future onRequest( 7 | RequestContext context, 8 | String id, 9 | ) async { 10 | return switch (context.request.method) { 11 | HttpMethod.get => _getUser(context, id), 12 | HttpMethod.patch => _updateUser(context, id), 13 | HttpMethod.delete => _deleteUser(context, id), 14 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 15 | }; 16 | } 17 | 18 | Future _getUser(RequestContext context, String id) async { 19 | final user = await context.read().userFromId(id); 20 | 21 | if (user == null) { 22 | return Response(statusCode: HttpStatus.forbidden); 23 | } else { 24 | if (user.id != id) { 25 | return Response(statusCode: HttpStatus.forbidden); 26 | } 27 | return Response.json( 28 | body: { 29 | 'id': user.id, 30 | 'name': user.name, 31 | 'username': user.username, 32 | }, 33 | ); 34 | } 35 | } 36 | 37 | Future _updateUser(RequestContext context, String id) async { 38 | final body = await context.request.json() as Map; 39 | final name = body['name'] as String?; 40 | final username = body['username'] as String?; 41 | final password = body['password'] as String?; 42 | 43 | if (name != null || username != null || password != null) { 44 | await context.read().updateUser( 45 | id: id, 46 | name: name, 47 | username: username, 48 | password: password, 49 | ); 50 | return Response(statusCode: HttpStatus.noContent); 51 | } else { 52 | return Response(statusCode: HttpStatus.badRequest); 53 | } 54 | } 55 | 56 | Future _deleteUser(RequestContext context, String id) async { 57 | final user = await context.read().userFromId(id); 58 | if (user == null) { 59 | return Response(statusCode: HttpStatus.forbidden); 60 | } else { 61 | if (user.id != id) { 62 | return Response(statusCode: HttpStatus.forbidden); 63 | } 64 | 65 | context.read().deleteUser(id); 66 | 67 | return Response(statusCode: HttpStatus.noContent); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tasklist_backend/routes/authentication/basic/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:dart_frog_auth/dart_frog_auth.dart'; 3 | import 'package:tasklist_backend/repository/user/user_repository.dart'; 4 | 5 | final userRepository = UserRepository(); 6 | 7 | Handler middleware(Handler handler) { 8 | return handler 9 | .use( 10 | basicAuthentication( 11 | authenticator: (context, username, password) { 12 | final repository = context.read(); 13 | return repository.userFromCredentials(username, password); 14 | }, 15 | applies: (RequestContext context) async => 16 | context.request.method != HttpMethod.post && 17 | context.request.method != HttpMethod.delete, 18 | ), 19 | ) 20 | .use(provider((_) => userRepository)); 21 | } 22 | -------------------------------------------------------------------------------- /tasklist_backend/routes/authentication/basic/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/user/user_repository.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.post => _createUser(context), 9 | HttpMethod.get => _getUser(context), 10 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 11 | }; 12 | } 13 | 14 | Future _getUser(RequestContext context) async { 15 | final body = await context.request.json() as Map; 16 | final username = body['username'] as String; 17 | final password = body['password'] as String; 18 | 19 | final user = await context 20 | .read() 21 | .userFromCredentials(username, password); 22 | 23 | if (user == null) { 24 | return Response(statusCode: HttpStatus.forbidden); 25 | } else { 26 | return Response.json( 27 | body: { 28 | 'id': user.id, 29 | 'name': user.name, 30 | 'username': user.username, 31 | }, 32 | ); 33 | } 34 | } 35 | 36 | Future _createUser(RequestContext context) async { 37 | final body = await context.request.json() as Map; 38 | final name = body['name'] as String?; 39 | final username = body['username'] as String?; 40 | final password = body['password'] as String?; 41 | 42 | final userRepository = context.read(); 43 | 44 | if (name != null && username != null && password != null) { 45 | final id = await userRepository.createUser( 46 | name: name, username: username, password: password); 47 | return Response.json(body: {'id': id}); 48 | } else { 49 | return Response(statusCode: HttpStatus.badRequest); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tasklist_backend/routes/authentication/bearer/[id].dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/user/user_repository.dart'; 5 | 6 | Future onRequest( 7 | RequestContext context, 8 | String id, 9 | ) async { 10 | return switch (context.request.method) { 11 | HttpMethod.get => _getUser(context, id), 12 | HttpMethod.patch => _updateUser(context, id), 13 | HttpMethod.delete => _deleteUser(context, id), 14 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 15 | }; 16 | } 17 | 18 | Future _getUser(RequestContext context, String id) async { 19 | final user = await context.read().userFromId(id); 20 | 21 | if (user == null) { 22 | return Response(statusCode: HttpStatus.forbidden); 23 | } else { 24 | if (user.id != id) { 25 | return Response(statusCode: HttpStatus.forbidden); 26 | } 27 | return Response.json( 28 | body: { 29 | 'id': user.id, 30 | 'name': user.name, 31 | 'username': user.username, 32 | }, 33 | ); 34 | } 35 | } 36 | 37 | Future _updateUser(RequestContext context, String id) async { 38 | final body = await context.request.json() as Map; 39 | final name = body['name'] as String?; 40 | final username = body['username'] as String?; 41 | final password = body['password'] as String?; 42 | 43 | if (name != null || username != null || password != null) { 44 | await context.read().updateUser( 45 | id: id, 46 | name: name, 47 | username: username, 48 | password: password, 49 | ); 50 | return Response(statusCode: HttpStatus.noContent); 51 | } else { 52 | return Response(statusCode: HttpStatus.badRequest); 53 | } 54 | } 55 | 56 | Future _deleteUser(RequestContext context, String id) async { 57 | final user = await context.read().userFromId(id); 58 | if (user == null) { 59 | return Response(statusCode: HttpStatus.forbidden); 60 | } else { 61 | if (user.id != id) { 62 | return Response(statusCode: HttpStatus.forbidden); 63 | } 64 | 65 | context.read().deleteUser(id); 66 | 67 | return Response(statusCode: HttpStatus.noContent); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tasklist_backend/routes/authentication/bearer/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:dart_frog_auth/dart_frog_auth.dart'; 3 | import 'package:tasklist_backend/repository/session/session_repository.dart'; 4 | import 'package:tasklist_backend/repository/user/user_repository.dart'; 5 | 6 | final userRepository = UserRepository(); 7 | final sessionRepository = SessionRepository(); 8 | 9 | Handler middleware(Handler handler) { 10 | return handler 11 | .use( 12 | bearerAuthentication( 13 | authenticator: (context, token) async { 14 | final sessionRepo = context.read(); 15 | final userRepo = context.read(); 16 | final session = sessionRepo.sessionFromToken(token); 17 | return session != null ? userRepo.userFromId(session.userId) : null; 18 | }, 19 | applies: (RequestContext context) async => 20 | context.request.method != HttpMethod.post && 21 | context.request.method != HttpMethod.get, 22 | ), 23 | ) 24 | .use(provider((_) => userRepository)) 25 | .use(provider((_) => sessionRepository)); 26 | } 27 | -------------------------------------------------------------------------------- /tasklist_backend/routes/authentication/bearer/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:dart_frog/dart_frog.dart'; 3 | import 'package:tasklist_backend/repository/session/session_repository.dart'; 4 | import 'package:tasklist_backend/repository/user/user_repository.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.post => _createUser(context), 9 | HttpMethod.get => _authenticateUser(context), 10 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 11 | }; 12 | } 13 | 14 | Future _createUser(RequestContext context) async { 15 | final body = await context.request.json() as Map; 16 | final name = body['name'] as String?; 17 | final username = body['username'] as String?; 18 | final password = body['password'] as String?; 19 | 20 | final userRepository = context.read(); 21 | 22 | if (name != null && username != null && password != null) { 23 | final id = await userRepository.createUser( 24 | name: name, username: username, password: password); 25 | return Response.json(body: {'id': id}); 26 | } else { 27 | return Response(statusCode: HttpStatus.badRequest); 28 | } 29 | } 30 | 31 | // Log in 32 | Future _authenticateUser(RequestContext context) async { 33 | final body = await context.request.json() as Map; 34 | final username = body['username'] as String?; 35 | final password = body['password'] as String?; 36 | 37 | final userRepository = context.read(); 38 | final sessionRepository = context.read(); 39 | 40 | if (username != null && password != null) { 41 | final user = await userRepository.userFromCredentials(username, password); 42 | 43 | if (user == null) { 44 | return Response(statusCode: HttpStatus.unauthorized); 45 | } else { 46 | final session = sessionRepository.createSession(user.id); 47 | return Response.json(body: {'token': session.token}); 48 | } 49 | } else { 50 | return Response(statusCode: HttpStatus.badRequest); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tasklist_backend/routes/cache/redis/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:redis/redis.dart'; 3 | 4 | final conn = RedisConnection(); 5 | 6 | Handler middleware(Handler handler) { 7 | return (context) async { 8 | Response response; 9 | 10 | try { 11 | final command = await conn.connect('localhost', 8091); 12 | 13 | try { 14 | await command.send_object( 15 | ['AUTH', 'default', 'X3tfQSHnltsa-yx8badihKv1tU2in9OV'], 16 | ); 17 | 18 | response = 19 | await handler.use(provider((_) => command)).call(context); 20 | } catch (e) { 21 | response = 22 | Response.json(body: {'success': false, 'message': e.toString()}); 23 | } 24 | } catch (e) { 25 | response = 26 | Response.json(body: {'success': false, 'message': e.toString()}); 27 | } 28 | 29 | return response; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /tasklist_backend/routes/cache/redis/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:redis/redis.dart'; 5 | 6 | //1 - logged in , 0 - logged out 7 | 8 | Future onRequest(RequestContext context) async { 9 | return switch (context.request.method) { 10 | HttpMethod.get => _getLoginStatus(context), 11 | HttpMethod.post => _setLoginStatus(context), 12 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 13 | }; 14 | } 15 | 16 | Future _getLoginStatus(RequestContext context) async { 17 | final value = await context 18 | .read() 19 | .send_object(['GET', 'loggedin']).then((value) => value); 20 | 21 | if (value == null) { 22 | const status = 0; 23 | await context.read().send_object(['SET', 'loggedin', status]); 24 | return Response(statusCode: HttpStatus.noContent); 25 | } else { 26 | return Response.json( 27 | body: {'success': true, 'message': int.parse(value.toString())}, 28 | ); 29 | } 30 | } 31 | 32 | Future _setLoginStatus(RequestContext context) async { 33 | final body = await context.request.json() as Map; 34 | final status = body['loggedin'] as int?; 35 | var success = false; 36 | 37 | try { 38 | await context.read().send_object(['SET', 'loggedin', status]); 39 | success = true; 40 | } catch (e) { 41 | success = false; 42 | } 43 | 44 | return Response.json(body: {'success': success}); 45 | } 46 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/fbase/[id].dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:firedart/firedart.dart'; 5 | 6 | Future onRequest( 7 | RequestContext context, 8 | String id, 9 | ) async { 10 | return switch (context.request.method) { 11 | HttpMethod.patch => _updateList(context, id), 12 | HttpMethod.delete => _deleteList(context, id), 13 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 14 | }; 15 | } 16 | 17 | Future _updateList(RequestContext context, String id) async { 18 | final body = await context.request.json() as Map; 19 | final name = body['name'] as String?; 20 | 21 | await Firestore.instance 22 | .collection('tasklists') 23 | .document(id) 24 | .update({'name': name}); 25 | 26 | return Response(statusCode: HttpStatus.noContent); 27 | } 28 | 29 | Future _deleteList(RequestContext context, String id) async { 30 | await Firestore.instance.collection('tasklists').document(id).delete().then( 31 | (value) { 32 | return Response(statusCode: HttpStatus.noContent); 33 | }, 34 | onError: (e) { 35 | return Response(statusCode: HttpStatus.badRequest); 36 | }, 37 | ); 38 | return Response(statusCode: HttpStatus.badRequest); 39 | } 40 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/fbase/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:firedart/firedart.dart'; 3 | 4 | Handler middleware(Handler handler) { 5 | return (context) async { 6 | if (!Firestore.initialized) { 7 | Firestore.initialize(''); 8 | } 9 | 10 | final response = await handler(context); 11 | 12 | 13 | 14 | return response; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/fbase/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:firedart/firedart.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.get => _getLists(context), 9 | HttpMethod.post => _createList(context), 10 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 11 | }; 12 | } 13 | 14 | Future _getLists(RequestContext context) async { 15 | final lists = >[]; 16 | 17 | await Firestore.instance.collection('tasklists').get().then((event) { 18 | for (final doc in event) { 19 | lists.add(doc.map); 20 | } 21 | }); 22 | 23 | return Response.json(body: lists.toString()); 24 | } 25 | 26 | Future _createList(RequestContext context) async { 27 | final body = await context.request.json() as Map; 28 | final name = body['name'] as String?; 29 | 30 | final list = {'name': name}; 31 | 32 | final id = 33 | await Firestore.instance.collection('tasklists').add(list).then((doc) { 34 | return doc.id; 35 | }); 36 | 37 | return Response.json(body: {'id': id}); 38 | } 39 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/mongodb/[id].dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mongo_dart/mongo_dart.dart'; 5 | 6 | Future onRequest( 7 | RequestContext context, 8 | String id, 9 | ) async { 10 | return switch (context.request.method) { 11 | HttpMethod.patch => _updateList(context, id), 12 | HttpMethod.delete => _deleteList(context, id), 13 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 14 | }; 15 | } 16 | 17 | Future _updateList(RequestContext context, String id) async { 18 | final body = await context.request.json() as Map; 19 | final name = body['name'] as String?; 20 | 21 | try { 22 | await context 23 | .read() 24 | .collection('lists') 25 | .updateOne(where.eq('id', id), modify.set('name', name)); 26 | 27 | return Response(statusCode: HttpStatus.noContent); 28 | } catch (e) { 29 | return Response(statusCode: HttpStatus.badRequest); 30 | } 31 | } 32 | 33 | Future _deleteList(RequestContext context, String id) async { 34 | await context.read().collection('lists').deleteOne({'id': id}).then( 35 | (value) { 36 | return Response(statusCode: HttpStatus.noContent); 37 | }, 38 | onError: (e) { 39 | return Response(statusCode: HttpStatus.badRequest); 40 | }, 41 | ); 42 | 43 | return Response(statusCode: HttpStatus.badRequest); 44 | } 45 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/mongodb/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:mongo_dart/mongo_dart.dart'; 3 | 4 | Handler middleware(Handler handler) { 5 | return (context) async { 6 | final db = await Db.create( 7 | 'mongodb+srv://:@/?retryWrites=true&w=majority'); 8 | 9 | if (!db.isConnected) { 10 | await db.open(); 11 | } 12 | 13 | final response = await handler.use(provider((_) => db)).call(context); 14 | 15 | await db.close(); 16 | 17 | return response; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/mongodb/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:mongo_dart/mongo_dart.dart'; 5 | import 'package:tasklist_backend/hash_extension.dart'; 6 | 7 | Future onRequest(RequestContext context) async { 8 | return switch (context.request.method) { 9 | HttpMethod.get => _getLists(context), 10 | HttpMethod.post => _createList(context), 11 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 12 | }; 13 | } 14 | 15 | Future _getLists(RequestContext context) async { 16 | final lists = await context.read().collection('lists').find().toList(); 17 | return Response.json(body: lists.toString()); 18 | } 19 | 20 | Future _createList(RequestContext context) async { 21 | final body = await context.request.json() as Map; 22 | final name = body['name'] as String?; 23 | 24 | final id = name?.hashValue; 25 | 26 | final list = {'id': id, 'name': name}; 27 | 28 | final result = await context.read().collection('lists').insertOne(list); 29 | 30 | return Response.json(body: {'id': result.id}); 31 | } 32 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/postgresql/[id].dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:postgres/postgres.dart'; 5 | 6 | Future onRequest( 7 | RequestContext context, 8 | String id, 9 | ) async { 10 | return switch (context.request.method) { 11 | HttpMethod.patch => _updateList(context, id), 12 | HttpMethod.delete => _deleteList(context, id), 13 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 14 | }; 15 | } 16 | 17 | Future _updateList(RequestContext context, String id) async { 18 | final body = await context.request.json() as Map; 19 | final name = body['name'] as String?; 20 | 21 | if (name != null) { 22 | try { 23 | final result = await context.read().query( 24 | "UPDATE lists SET name = " + 25 | "'" + 26 | name + 27 | " ' " + 28 | "WHERE id = " + 29 | " '" + 30 | id + 31 | " '"); 32 | 33 | if (result.affectedRowCount == 1) { 34 | return Response.json(body: {'success': true}); 35 | } else { 36 | return Response.json(body: {'success': false}); 37 | } 38 | } catch (e) { 39 | return Response(statusCode: HttpStatus.connectionClosedWithoutResponse); 40 | } 41 | } else { 42 | return Response(statusCode: HttpStatus.badRequest); 43 | } 44 | } 45 | 46 | Future _deleteList(RequestContext context, String id) async { 47 | await context 48 | .read() 49 | .query("DELETE FROM lists WHERE id = " + " '" + id + " '") 50 | .then( 51 | (value) { 52 | return Response(statusCode: HttpStatus.noContent); 53 | }, 54 | onError: (e) { 55 | return Response(statusCode: HttpStatus.badRequest); 56 | }, 57 | ); 58 | return Response(statusCode: HttpStatus.badRequest); 59 | } 60 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/postgresql/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:postgres/postgres.dart'; 3 | 4 | Handler middleware(Handler handler) { 5 | return (context) async { 6 | final connection = PostgreSQLConnection( 7 | '', 8 | 5432, 9 | '', 10 | username: '', 11 | password: '', 12 | ); 13 | 14 | await connection.open(); 15 | 16 | final response = await handler 17 | .use(provider((_) => connection)) 18 | .call(context); 19 | 20 | await connection.close(); 21 | 22 | return response; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /tasklist_backend/routes/db/postgresql/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:postgres/postgres.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.get => _getLists(context), 9 | HttpMethod.post => _createList(context), 10 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 11 | }; 12 | } 13 | 14 | Future _getLists(RequestContext context) async { 15 | final lists = >[]; 16 | final results = await context 17 | .read() 18 | .query('SELECT id , name FROM lists'); 19 | 20 | for (final row in results) { 21 | lists.add({'id': row[0], 'name': row[1]}); 22 | } 23 | 24 | return Response.json(body: lists.toString()); 25 | } 26 | 27 | Future _createList(RequestContext context) async { 28 | final body = await context.request.json() as Map; 29 | final name = body['name'] as String?; 30 | 31 | if (name != null) { 32 | try { 33 | final result = await context.read().query( 34 | "INSERT INTO lists (name) VALUES (" + "'" + name + "'" + ") "); 35 | 36 | if (result.affectedRowCount == 1) { 37 | return Response.json(body: {'success': true}); 38 | } else { 39 | return Response.json(body: {'success': false}); 40 | } 41 | } catch (e) { 42 | return Response(statusCode: HttpStatus.connectionClosedWithoutResponse); 43 | } 44 | } else { 45 | return Response(statusCode: HttpStatus.badRequest); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tasklist_backend/routes/files/_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:tasklist_backend/config.dart'; 3 | 4 | Handler middleware(Handler handler) { 5 | return handler 6 | .use(requestLogger()) 7 | .use(provider((_) => Configuration())); 8 | } 9 | -------------------------------------------------------------------------------- /tasklist_backend/routes/files/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:dart_frog/dart_frog.dart'; 3 | import 'package:tasklist_backend/config.dart'; 4 | 5 | Future onRequest(RequestContext context) async { 6 | final config = await context.read().getFileConfigurations(); 7 | 8 | return switch (context.request.method) { 9 | HttpMethod.get => _downloadFiles(context, config), 10 | HttpMethod.post => _uploadFiles(context, config), 11 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 12 | }; 13 | } 14 | 15 | Future _uploadFiles( 16 | RequestContext context, Map config) async { 17 | final formData = await context.request.formData(); 18 | final file = formData.files['file']; 19 | 20 | print(file); 21 | 22 | if (file == null) { 23 | return Response(statusCode: HttpStatus.badRequest); 24 | } 25 | 26 | final publicPath = config['public_path'] as String; 27 | try { 28 | File(publicPath + file.name).writeAsBytesSync(await file.readAsBytes()); 29 | } catch (e, s) { 30 | print('Failed to write into $file: $e\nStacktrace: $s'); 31 | } 32 | 33 | return Response.json( 34 | body: {'message': 'Successfully uploaded ${file.name}'}, 35 | ); 36 | } 37 | 38 | Future _downloadFiles( 39 | RequestContext context, 40 | Map config, 41 | ) async { 42 | final dir = Directory(config['public_path'] as String); 43 | final entities = await dir.list().toList(); 44 | final files = []; 45 | try { 46 | for (final name in entities) { 47 | files.add(name.uri.pathSegments.last); 48 | } 49 | } catch (e) { 50 | return Response(statusCode: HttpStatus.badRequest); 51 | } 52 | 53 | return Response.json(body: files); 54 | } 55 | -------------------------------------------------------------------------------- /tasklist_backend/routes/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/lists/list_Repository.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.get => _getLists(context), 9 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 10 | }; 11 | } 12 | 13 | Future _getLists(RequestContext context) async { 14 | final lists = context.read().getAllLists(); 15 | return Response.json(body: lists); 16 | } 17 | -------------------------------------------------------------------------------- /tasklist_backend/routes/items/[id].dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/items/item_Repository.dart'; 5 | 6 | Future onRequest( 7 | RequestContext context, 8 | String id, 9 | ) async { 10 | return switch (context.request.method) { 11 | HttpMethod.get => _getItemsByList(context, id), 12 | HttpMethod.patch => _updateItem(context, id), 13 | HttpMethod.delete => _deleteItem(context, id), 14 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 15 | }; 16 | } 17 | 18 | Future _getItemsByList(RequestContext context, String id) async { 19 | final tlist = context.read().getItemsByList(id); 20 | 21 | return Response.json(body: tlist); 22 | } 23 | 24 | Future _updateItem(RequestContext context, String id) async { 25 | final listRepository = context.read(); 26 | 27 | final body = await context.request.json() as Map; 28 | final name = body['name'] as String?; 29 | final listid = body['listid'] as String?; 30 | final description = body['description'] as String?; 31 | final status = body['status'] as bool?; 32 | 33 | if (name != null && listid != null && description != null && status != null) { 34 | await listRepository.updateItem( 35 | id: id, 36 | name: name, 37 | listid: listid, 38 | description: description, 39 | status: status); 40 | return Response(statusCode: HttpStatus.noContent); 41 | } else { 42 | return Response(statusCode: HttpStatus.badRequest); 43 | } 44 | } 45 | 46 | Future _deleteItem(RequestContext context, String id) async { 47 | context.read().deleteItem(id); 48 | return Response(statusCode: HttpStatus.noContent); 49 | } 50 | -------------------------------------------------------------------------------- /tasklist_backend/routes/items/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/items/item_Repository.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.post => _createItem(context), 9 | HttpMethod.get => _getAllItems(context), 10 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 11 | }; 12 | } 13 | 14 | Future _getAllItems(RequestContext context) async { 15 | final items = context.read().getAllItems(); 16 | 17 | print(items); 18 | 19 | return Response.json(body: items); 20 | } 21 | 22 | Future _createItem(RequestContext context) async { 23 | final body = await context.request.json() as Map; 24 | final listid = body['listid'] as String?; 25 | final name = body['name'] as String?; 26 | final description = body['description'] as String?; 27 | final status = body['status'] as bool?; 28 | 29 | final itemRepository = context.read(); 30 | 31 | if (name != null && listid != null && description != null && status != null) { 32 | final id = itemRepository.createItem( 33 | name: name, 34 | listid: listid, 35 | description: description, 36 | status: status, 37 | ); 38 | 39 | return Response.json(body: {'id': id}); 40 | } else { 41 | return Response(statusCode: HttpStatus.badRequest); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tasklist_backend/routes/lists/[id].dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/lists/list_Repository.dart'; 5 | 6 | Future onRequest( 7 | RequestContext context, 8 | String id, 9 | ) async { 10 | return switch (context.request.method) { 11 | HttpMethod.get => _getList(context, id), 12 | HttpMethod.patch => _updateList(context, id), 13 | HttpMethod.delete => _deleteList(context, id), 14 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 15 | }; 16 | } 17 | 18 | Future _getList(RequestContext context, String id) async { 19 | final tlist = await context.read().listById(id); 20 | 21 | if (tlist?.id != id) { 22 | return Response(statusCode: HttpStatus.forbidden); 23 | } 24 | 25 | return Response.json(body: {'id': tlist!.id, 'name': tlist.name}); 26 | } 27 | 28 | Future _updateList(RequestContext context, String id) async { 29 | final listRepository = context.read(); 30 | 31 | final body = await context.request.json() as Map; 32 | final name = body['name'] as String?; 33 | 34 | if (name != null) { 35 | await listRepository.updateList(id: id, name: name); 36 | return Response.json(body: {'id': id}); 37 | } else { 38 | return Response(statusCode: HttpStatus.badRequest); 39 | } 40 | } 41 | 42 | Future _deleteList(RequestContext context, String id) async { 43 | context.read().deleteList(id); 44 | return Response(statusCode: HttpStatus.noContent); 45 | } 46 | -------------------------------------------------------------------------------- /tasklist_backend/routes/lists/index.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:dart_frog/dart_frog.dart'; 4 | import 'package:tasklist_backend/repository/lists/list_Repository.dart'; 5 | 6 | Future onRequest(RequestContext context) async { 7 | return switch (context.request.method) { 8 | HttpMethod.post => _createList(context), 9 | _ => Future.value(Response(statusCode: HttpStatus.methodNotAllowed)) 10 | }; 11 | } 12 | 13 | Future _createList(RequestContext context) async { 14 | final body = await context.request.json() as Map; 15 | 16 | final name = body['name'] as String?; 17 | 18 | final listRepository = context.read(); 19 | 20 | if (name != null) { 21 | final id = listRepository.createList(name: name); 22 | 23 | return Response.json(body: {'id': id}); 24 | } else { 25 | return Response(statusCode: HttpStatus.badRequest); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tasklist_backend/routes/ws.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_frog/dart_frog.dart'; 2 | import 'package:dart_frog_web_socket/dart_frog_web_socket.dart'; 3 | 4 | Future onRequest(RequestContext context) async { 5 | final handler = webSocketHandler((channel, protocol) { 6 | print('connected'); 7 | 8 | channel.stream.listen( 9 | (message) { 10 | print(message); 11 | 12 | channel.sink.add('echo => $message!'); 13 | }, 14 | onDone: () => print('disconnected'), 15 | ); 16 | }); 17 | 18 | return handler(context); 19 | } 20 | --------------------------------------------------------------------------------