Skip to content

Commit

Permalink
Merge pull request #91 from TaskWeaver/87-combine-projectviewmodel-pr…
Browse files Browse the repository at this point in the history
…ojectsviewmodel

87 combine projectviewmodel projectsviewmodel
  • Loading branch information
jjoonleo authored Apr 20, 2024
2 parents b5c021e + 9447060 commit 4242c09
Show file tree
Hide file tree
Showing 18 changed files with 434 additions and 419 deletions.
16 changes: 9 additions & 7 deletions front/lib/app/config/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,16 @@ final router = GoRouter(initialLocation: '/', routes: [
path: 'teamDetail/:teamId',
name: 'teamDetail/:teamId',
builder: (context, state) {
return TeamDetailView(state.pathParameters['teamId']!);
return TeamDetailView(int.parse(state.pathParameters['teamId']!));
},
),
GoRoute(
path: 'projectDetail/:projectId',
name: 'projectDetail/:projectId',
path: 'projectDetail/:teamId/:projectId',
name: 'projectDetail/:teamId/:projectId',
builder: (context, state) => ProjectDetailScreen(
projectId: int.parse(state.pathParameters['projectId']!)),
teamId: int.parse(state.pathParameters['teamId']!),
projectId: int.parse(state.pathParameters['projectId']!),
),
),
GoRoute(
path: 'projectCreate/:teamId',
Expand All @@ -71,10 +73,10 @@ final router = GoRouter(initialLocation: '/', routes: [
teamId: int.parse(state.pathParameters['teamId']!)),
),
GoRoute(
path: 'projectUpdate',
name: 'projectUpdate',
path: 'projectUpdate/:teamId',
name: 'projectUpdate/:teamId',
builder: (context, state) =>
ProjectUpdateScreen(project: state.extra! as Project),
ProjectUpdateScreen(project: state.extra! as Project, teamId: int.parse(state.pathParameters['teamId']!)),
),
GoRoute(
path: 'main',
Expand Down
46 changes: 46 additions & 0 deletions front/lib/core/config/custom_interceptor.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import 'dart:io';

import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'
hide Options;
import 'package:front/core/const/const.dart';
import 'package:front/core/utils/exception.dart';
import 'package:front/core/utils/failure.dart';

///토큰을 헤더에 추가, 에러를 다루기 위한 인터셉터
class CustomInterceptor extends Interceptor {
Expand Down Expand Up @@ -101,3 +107,43 @@ class CustomInterceptor extends Interceptor {
// return handler.reject(err);
// }
}

mixin ErrorHandler {
Future<Either<Failure, T>> catchError<T>(Future<T> Function() f) async {
try {
return Future.value(Right(await f()));
} on DioException catch (err) {
debugPrint(err.response?.data.toString());
switch (err.type) {
case DioExceptionType.badCertificate:
return Future.value(Left(ResponseFailure.unknown.getFailure()));
case DioExceptionType.badResponse:
return Future.value(Left(ResponseFailure.values
.firstWhere((value) => value.code == err.response?.statusCode,
orElse: () => ResponseFailure.unknown)
.failure
.copyWith(message: err.response?.data['message'])));
case DioExceptionType.cancel:
return Future.value(Left(ResponseFailure.cancel.getFailure()));
case DioExceptionType.connectionError:
return Future.value(
Left(ResponseFailure.connectionError.getFailure()));
case DioExceptionType.connectionTimeout:
return Future.value(
Left(ResponseFailure.connectionTimeout.getFailure()));
case DioExceptionType.receiveTimeout:
return Future.value(
Left(ResponseFailure.receiveTimeout.getFailure()));
case DioExceptionType.sendTimeout:
return Future.value(Left(ResponseFailure.sendTimeout.getFailure()));
case DioExceptionType.unknown:
return Future.value(Left(ResponseFailure.unknown.getFailure()));
}
} on ServerException {
return Future.value(const Left(ServerFailure('An error has occurred')));
} on SocketException {
return Future.value(
const Left(ServerFailure('Failed to connect to the network')));
}
}
}
16 changes: 2 additions & 14 deletions front/lib/core/config/providers/dio.dart
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
import 'package:dio/dio.dart';
import 'package:front/core/config/custom_interceptor.dart';
import 'package:front/core/config/providers/secure_storage.dart';
import 'package:front/core/network_handling/app_dio.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'dio.g.dart';

@riverpod
Dio dio(DioRef ref) {
var dio = Dio(
BaseOptions(
baseUrl:
'http://ec2-3-34-95-39.ap-northeast-2.compute.amazonaws.com:8083',
connectTimeout: const Duration(milliseconds: 5000),
receiveTimeout: const Duration(milliseconds: 3000),
),
);

var storage = ref.watch(secureStorageProvider);

dio.interceptors.add(
CustomInterceptor(storage: storage),
);
var dio = AppDio.instance;

return dio;
}
1 change: 1 addition & 0 deletions front/lib/core/network_handling/app_dio.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class _AppDio with DioMixin implements Dio {
connectTimeout: Duration(milliseconds: 30000),
receiveTimeout: Duration(milliseconds: 30000),
sendTimeout: Duration(milliseconds: 30000),
baseUrl: 'http://ec2-3-34-95-39.ap-northeast-2.compute.amazonaws.com:8083',
receiveDataWhenStatusError: true,
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:front/core/const/const.dart';

Expand All @@ -9,14 +10,16 @@ class TokenInterceptor implements InterceptorsWrapper {

@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
final accessToken = options.headers.remove('accessToken') == 'true';
if(options.headers['accessToken'] == 'true') {
debugPrint(options.headers.toString());

if (!accessToken) return handler.next(options);
options.headers.remove('accessToken');

final token = await storage.read(key: accessTokenKey);
final token = await storage.read(key: accessTokenKey);

if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
}
return handler.next(options);
}
Expand Down
60 changes: 58 additions & 2 deletions front/lib/core/utils/failure.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import 'package:equatable/equatable.dart';

abstract class Failure extends Equatable {
class Failure extends Equatable {
const Failure(this.message);
final String message;

Failure copyWith({String? message}) {
return Failure(message ?? this.message);
}

@override
List<Object> get props => [message];
}
Expand All @@ -18,4 +22,56 @@ class ConnectionFailure extends Failure {

class DatabaseFailure extends Failure {
const DatabaseFailure(String message) : super(message);
}
}

enum ResponseFailure {
badRequest(
code: 400, message: 'badRequest', failure: ServerFailure('badRequest')),
forbidden(
code: 403, message: 'forbidden', failure: ServerFailure('forbidden')),
unauthorized(
code: 401,
message: 'unauthorized',
failure: ServerFailure('unauthorized')),
notFound(code: 404, message: 'notFound', failure: ServerFailure('notFound')),

cancel(code: 701, message: 'cancel', failure: ServerFailure('cancel')),
connectionError(
code: 702,
message: 'connectionError',
failure: ServerFailure('connectionError')),
connectionTimeout(
code: 703,
message: 'connectionTimeout',
failure: ServerFailure('connectionTimeout')),
receiveTimeout(
code: 704,
message: 'receiveTimeout',
failure: ServerFailure('receiveTimeout')),
sendTimeout(
code: 705, message: 'sendTimeout', failure: ServerFailure('sendTimeout')),
unknown(code: 706, message: 'unknown', failure: ServerFailure('unknown'));

factory ResponseFailure.getByCode(int code) {
return ResponseFailure.values.firstWhere((value) => value.code == code,
orElse: () => ResponseFailure.unknown);
}

const ResponseFailure(
{required this.code, required this.message, required this.failure});

final int code;
final String message;
final Failure failure;
Failure getFailure() {
return ServerFailure(message);
}
}

enum ResponseSuccess {
success(200),
created(201);

const ResponseSuccess(this.code);
final int code;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:front/core/network_handling/app_dio.dart';

import 'package:front/core/utils/exception.dart';
import 'package:front/features/project/data/models/project.dart';
Expand All @@ -15,16 +16,20 @@ abstract class ProjectRemoteDataSource {
}

class ProjectRemoteDataSourceImpl implements ProjectRemoteDataSource {
ProjectRemoteDataSourceImpl({required this.dio});
final Dio dio;
ProjectRemoteDataSourceImpl();
final Dio dio = AppDio.instance;

@override
Future<List<ProjectModel>> getProjectsByTeamId(int teamId) async {
try {
dio.options.headers = {'accessToken': 'true'};
debugPrint('teamId: $teamId');
var response = await dio.get(
'/v1/team/$teamId/projects',
options: Options(
headers: {
'accessToken': 'true',
},
),
);

if (response.statusCode == 200 && response.data?['resultCode'] == 200) {
Expand All @@ -35,33 +40,34 @@ class ProjectRemoteDataSourceImpl implements ProjectRemoteDataSource {
} else {
throw ServerException();
}
} on DioException catch (e) {
debugPrint(e.response?.data.toString());
throw ServerException();
} on DioException {
rethrow;
}
}

@override
Future<ProjectModel> getProjectById(int projectId) async {
try {
dio.options.headers = {'accessToken': 'true'};
var response = await dio.get('/v1/project/$projectId');
var response = await dio.get('/v1/project/$projectId',options: Options(
headers: {
'accessToken': 'true',
},
),);

if (response.statusCode == 200 && response.data?['resultCode'] == 200) {
return ProjectModel.fromJson(response.data['result']);
} else {
throw ServerException();
}
} on DioException {
throw ServerException();
rethrow;
}
}

@override
Future<ProjectModel> createProject(
ProjectRequestModel project, int teamId) async {
try {
dio.options.headers = {'accessToken': 'true'};
var response = await dio.post(
'/v1/team/$teamId/project',
data: project.toJson(),
Expand All @@ -76,45 +82,51 @@ class ProjectRemoteDataSourceImpl implements ProjectRemoteDataSource {
} else {
throw ServerException();
}
} on DioException catch (e) {
debugPrint(e.response?.data.toString());
throw ServerException();
} on DioException {
rethrow;
}
}

@override
Future<void> deleteProjectById(int projectId) async {
try {
dio.options.headers = {'accessToken': 'true'};
var response = await dio.delete('/v1/project/$projectId');
var response = await dio.delete('/v1/project/$projectId',options: Options(
headers: {
'accessToken': 'true',
},
),);

if (response.statusCode == 200 && response.data?['resultCode'] == 200) {
return;
} else {
throw ServerException();
}
} on DioException catch (e){
debugPrint(e.response?.toString());
throw ServerException();
} on DioException {
rethrow;
}
}

@override
Future<ProjectRequestModel> updateProjectById(
ProjectRequestModel project, int projectId) async {
try {
dio.options.headers = {'accessToken': 'true'};
var response =
await dio.patch('/v1/project/$projectId', data: project.toJson(),);
var response = await dio.patch(
'/v1/project/$projectId',
data: project.toJson(),
options: Options(
headers: {
'accessToken': 'true',
},
),
);

if (response.statusCode == 204 && response.data?['resultCode'] == 204) {
return project;
} else {
throw ServerException();
}
} on DioException catch (e) {
debugPrint(e.response?.toString());
throw ServerException();
} on DioException {
rethrow;
}
}
}
2 changes: 1 addition & 1 deletion front/lib/features/project/data/data_sources/riverpod.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ProjectRemoteDataSource projectRemoteDataSource(
ProjectRemoteDataSourceRef ref,
) {
var dio = ref.read(dioProvider);
return ProjectRemoteDataSourceImpl(dio: dio);
return ProjectRemoteDataSourceImpl();
}

@riverpod
Expand Down
Loading

0 comments on commit 4242c09

Please sign in to comment.