diff --git a/.github/workflows/vania-dart.yml b/.github/workflows/vania-dart.yml new file mode 100644 index 0000000..91c0c64 --- /dev/null +++ b/.github/workflows/vania-dart.yml @@ -0,0 +1,35 @@ +name: Vania Dart + +on: + push: + branches: [ "main", "dev"] + pull_request: + branches: [ "main", "dev"] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup Dart + uses: dart-lang/setup-dart@v1.2 + with: + sdk: stable + + # Get Flutter packages + - name: Install dependencies + run: dart pub get + + # Check formatting + - name: Format check + run: dart format --output=none --set-exit-if-changed . + + # Analyze the source code + - name: Analyze project source + run: dart analyze + + # Run tests + - name: Run tests + run: dart test diff --git a/CHANGELOG.md b/CHANGELOG.md index 62549c0..d414260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,14 @@ -## 0.0.3+1 +## 0.1.0 -- Fixed bug: Authentication refresh token +- Initial beta release +- Fixed a bug related to WebSocket data events +- Corrected authentication check functionality +- Added `isAuthorized` feature +- Exported `query_builder` from Eloquent package for enhanced functionality +## 0.0.4 + +- Fixed bug: Authentication refresh token ## 0.0.3+1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ff4833a..c37cd9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,14 +2,14 @@ ## Creating a Pull Request -Before creating a pull request please: +Before creating a pull request, please follow these steps: -1. Fork the repository and create your branch from `main`. +1. Fork the repository and create your branch from `dev`. 2. Install all dependencies (`dart pub get`). 3. Squash your commits and ensure you have a meaningful, [semantic](https://www.conventionalcommits.org/en/v1.0.0/) commit message. 4. Add tests! Pull Requests without 100% test coverage will not be approved. 5. Ensure the existing test suite passes locally. 6. Format your code (`dart format .`). 7. Analyze your code (`dart analyze --fatal-infos --fatal-warnings .`). -8. Create the Pull Request. +8. Create the Pull Request targeting the `dev` branch. 9. Verify that all status checks are passing. diff --git a/lib/src/authentication/authentication.dart b/lib/src/authentication/authentication.dart index 2a6e5a5..80097d0 100644 --- a/lib/src/authentication/authentication.dart +++ b/lib/src/authentication/authentication.dart @@ -11,7 +11,7 @@ class Auth { String _userGuard = 'default'; - //Auth([String guard = 'default']) : _userGuard = guard; + bool _isAuthorized = false; final Map _user = {}; @@ -25,6 +25,8 @@ class Auth { return this; } + bool get isAuthorized => _isAuthorized; + Map? user() => _user[_userGuard]; dynamic id() => _user[_userGuard]['id']; @@ -44,20 +46,24 @@ class Auth { .refreshToken(token.replaceFirst('Bearer ', ''), _userGuard, expiresIn); } - Future check(String token) async { - Model? authenticatable = - Config().get('auth')['guards'][_userGuard]['provider']; + Future check(String token, {Map? user}) async { + Map payload = HasApiTokens() + .verify(token.replaceFirst('Bearer ', ''), _userGuard, 'access_token'); + + if (user == null) { + Model? authenticatable = + Config().get('auth')['guards'][_userGuard]['provider']; - if (authenticatable == null) { - throw InvalidArgumentException('Authenticatable class not found'); + if (authenticatable == null) { + throw InvalidArgumentException('Authenticatable class not found'); + } + user = + await authenticatable.query().where('id', '=', payload['id']).first(); } - Map payload = HasApiTokens() - .verify(token.replaceFirst('Bearer ', ''), _userGuard, 'access_token'); - Map? user = - await authenticatable.query().where('id', '=', payload['id']).first(); if (user != null) { _user[_userGuard] = user; + _isAuthorized = true; return true; } else { throw Unauthenticated(message: 'Invalid token'); diff --git a/lib/src/database/migration.dart b/lib/src/database/migration.dart index 6b1715f..0f56e44 100644 --- a/lib/src/database/migration.dart +++ b/lib/src/database/migration.dart @@ -177,7 +177,7 @@ class Migration { } void index(ColumnIndex type, String name, List columns) { - if (type == ColumnIndex.INDEX) { + if (type == ColumnIndex.indexKey) { indexes.add('INDEX `$name` (${columns.map((e) => "`$e`").join(',')})'); } else { indexes.add( diff --git a/lib/src/enum/column_index.dart b/lib/src/enum/column_index.dart index 9c95d21..8351c0e 100644 --- a/lib/src/enum/column_index.dart +++ b/lib/src/enum/column_index.dart @@ -1,6 +1,6 @@ enum ColumnIndex { unique, - INDEX, + indexKey, flutext, spatial, } diff --git a/lib/src/http/request/request_handler.dart b/lib/src/http/request/request_handler.dart index 39a50cb..af9fb7c 100644 --- a/lib/src/http/request/request_handler.dart +++ b/lib/src/http/request/request_handler.dart @@ -9,10 +9,12 @@ import 'package:vania/src/websocket/web_socket_handler.dart'; import 'package:vania/vania.dart'; Future httpRequestHandler(HttpRequest req) async { + /// Check the incoming request is web socket or not if (Config().get("websocket") && WebSocketTransformer.isUpgradeRequest(req)) { WebSocketHandler().handler(req); } else { try { + /// Check if cors is enabled HttpCros(req); Request request = @@ -31,13 +33,14 @@ Future httpRequestHandler(HttpRequest req) async { await middlewares.first.handle(request); } + /// Controller and method handler ControllerHandler(route: route, request: request).call(); } on BaseHttpException catch (e) { e.call().makeResponse(req.response); } on InvalidArgumentException catch (e) { print(e.message); } catch (e) { - print("catch ${e.toString()}"); + print(e.toString()); } } } diff --git a/lib/src/http/validation/rules.dart b/lib/src/http/validation/rules.dart index ee0f265..b77c2b9 100644 --- a/lib/src/http/validation/rules.dart +++ b/lib/src/http/validation/rules.dart @@ -127,12 +127,12 @@ class Rules { /// check field character is given max length static bool maxLength(Map data, dynamic value, String max) { - return value.toString().length < num.parse(max.toString()); + return value.toString().length <= num.parse(max.toString()); } /// check field character is given min length static bool minLength(Map data, dynamic value, String min) { - return value.toString().length > num.parse(min.toString()); + return value.toString().length >= num.parse(min.toString()); } /// check field character is between given length diff --git a/lib/src/websocket/web_socket_handler.dart b/lib/src/websocket/web_socket_handler.dart index 3dec324..1432335 100644 --- a/lib/src/websocket/web_socket_handler.dart +++ b/lib/src/websocket/web_socket_handler.dart @@ -29,11 +29,11 @@ class WebSocketHandler implements WebSocketEvent { websocket.listen((data) { Map payload = jsonDecode(data); - String event = payload[WEB_SOCKET_EVENT_KEY]; + String event = payload[webScoketEventKey]; /// client join the room - if (event == WEB_SOCKET_JOIN_ROOM_EVENT_NAME) { - String? roomId = payload[WEB_SOCKET_ROOM_KEY]; + if (event == webSocketJoinRoomEventName) { + String? roomId = payload[webSocketRoomKey]; if (roomId != null) { _session.joinRoom(sessionId, roomId); client.joinRoom(roomId); @@ -42,8 +42,8 @@ class WebSocketHandler implements WebSocketEvent { } /// client left the room - if (event == WEB_SOCKET_LEFT_ROOM_EVENT_NAME) { - String? roomId = payload[WEB_SOCKET_ROOM_KEY]; + if (event == webSocketLeftRoomEventName) { + String? roomId = payload[webSocketRoomKey]; if (roomId != null) { _session.leftRoom(sessionId, roomId); client.leftRoom(roomId); @@ -57,7 +57,7 @@ class WebSocketHandler implements WebSocketEvent { /// response /// }); /// ``` - dynamic message = payload[WEB_SOCKET_MESSAGE_KEY]; + dynamic message = payload[webSocketMessageKey]; Function? controller = _events[event]; diff --git a/lib/src/websocket/websocket_constants.dart b/lib/src/websocket/websocket_constants.dart index f64916d..fe22032 100644 --- a/lib/src/websocket/websocket_constants.dart +++ b/lib/src/websocket/websocket_constants.dart @@ -1,11 +1,11 @@ -const String WEB_SOCKET_JOIN_ROOM_EVENT_NAME = 'joinRoom'; +const String webSocketJoinRoomEventName = 'joinRoom'; -const String WEB_SOCKET_LEFT_ROOM_EVENT_NAME = 'leftRoom'; +const String webSocketLeftRoomEventName = 'leftRoom'; -const String WEB_SOCKET_EVENT_KEY = 'event'; +const String webScoketEventKey = 'event'; -const String WEB_SOCKET_MESSAGE_KEY = 'message'; +const String webSocketMessageKey = 'data'; -const String WEB_SOCKET_SENDER_KEY = 'sender'; +const String webSocketSenderKey = 'sender'; -const String WEB_SOCKET_ROOM_KEY = 'room'; +const String webSocketRoomKey = 'room'; diff --git a/lib/vania.dart b/lib/vania.dart index ebb8b0a..40c47a4 100644 --- a/lib/vania.dart +++ b/lib/vania.dart @@ -37,6 +37,7 @@ export 'src/database/mysql_driver.dart'; export 'src/database/postgresql_driver.dart'; export 'src/database/migration.dart'; export 'src/enum/column_index.dart'; +export 'package:eloquent/src/query/query_builder.dart'; export 'src/authentication/authentication.dart'; export 'src/authentication/authenticate.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 5d9cd8f..b8f9c7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: vania description: Fast, simple, and powerful backend framework for Dart built with ❤️ -version: 0.0.4 +version: 0.1.0 homepage: https://vdart.dev repository: https://github.com/vania-dart/framework issue_tracker: https://github.com/vania-dart/framework/issues @@ -12,10 +12,11 @@ screenshots: path: assets/logo.png environment: - sdk: ^3.2.3 + sdk: ^3.0.0 # Add regular dependencies here. dependencies: + crypto: ^3.0.3 dart_jsonwebtoken: ^2.13.0 eloquent: ^3.0.0 meta: ^1.12.0 diff --git a/test/unit/route_test.dart b/test/unit/route_test.dart index ee0d2c0..8218fd3 100644 --- a/test/unit/route_test.dart +++ b/test/unit/route_test.dart @@ -12,42 +12,42 @@ void main() { Router.get('/get', () {}); RouteData data = Router().routes.first; expect(data.path, '/get'); - expect(data.method, 'GET'); + expect(data.method, 'get'); }); test('post route', () { Router.post('/post', () {}); RouteData data = Router().routes.first; expect(data.path, '/post'); - expect(data.method, 'POST'); + expect(data.method, 'post'); }); test('delete route', () { Router.delete('/delete', () {}); RouteData data = Router().routes.first; expect(data.path, '/delete'); - expect(data.method, 'DELETE'); + expect(data.method, 'delete'); }); test('put route', () { Router.put('/put', () {}); RouteData data = Router().routes.first; expect(data.path, '/put'); - expect(data.method, 'PUT'); + expect(data.method, 'put'); }); test('patch route', () { Router.patch('/patch', () {}); RouteData data = Router().routes.first; expect(data.path, '/patch'); - expect(data.method, 'PATCH'); + expect(data.method, 'patch'); }); test('options route', () { Router.options('/options', () {}); RouteData data = Router().routes.first; expect(data.path, '/options'); - expect(data.method, 'OPTIONS'); + expect(data.method, 'options'); }); test('group route test', () { @@ -62,22 +62,22 @@ void main() { List data = Router().routes; expect(data[0].path, '/get'); - expect(data[0].method, 'GET'); + expect(data[0].method, 'get'); expect(data[1].path, '/post'); - expect(data[1].method, 'POST'); + expect(data[1].method, 'post'); expect(data[2].path, '/delete'); - expect(data[2].method, 'DELETE'); + expect(data[2].method, 'delete'); expect(data[3].path, '/put'); - expect(data[3].method, 'PUT'); + expect(data[3].method, 'put'); expect(data[4].path, '/patch'); - expect(data[4].method, 'PATCH'); + expect(data[4].method, 'patch'); expect(data[5].path, '/options'); - expect(data[5].method, 'OPTIONS'); + expect(data[5].method, 'options'); }); tearDownAll(() {