uploading picture from flutter to webapi implemented

This commit is contained in:
LilleBRG 2024-09-09 15:36:32 +02:00
parent c43144e028
commit 873fd44f1c
9 changed files with 140 additions and 77 deletions

View File

@ -26,7 +26,7 @@ namespace API.Application.Users.Queries
Id = user.Id, Id = user.Id,
Email = user.Email, Email = user.Email,
Username = user.Username, Username = user.Username,
ProfilePictureURL = user.ProfilePicture, ProfilePicture = user.ProfilePicture,
}).ToList(); }).ToList();
return userDTOs; return userDTOs;
} }

View File

@ -24,7 +24,7 @@ namespace API.Application.Users.Queries
return new ConflictObjectResult(new { message = "No user on given Id" }); return new ConflictObjectResult(new { message = "No user on given Id" });
} }
return new OkObjectResult(new { id = user.Id, email = user.Email, username = user.Username, profilePictureURL = user.ProfilePicture, createdAt = user.CreatedAt }); return new OkObjectResult(new { id = user.Id, email = user.Email, username = user.Username, profilePicture = user.ProfilePicture, createdAt = user.CreatedAt });
} }

View File

@ -75,7 +75,7 @@ namespace API.Controllers
[Authorize] [Authorize]
[HttpPut] [HttpPut]
public async Task<IActionResult> PutUser(UpdateUserDTO UpdateUserDTO) public async Task<IActionResult> PutUser([FromForm ]UpdateUserDTO UpdateUserDTO)
{ {
return await _updateUser.Handle(UpdateUserDTO); return await _updateUser.Handle(UpdateUserDTO);
} }

View File

@ -17,7 +17,7 @@ public class UserDTO
public string Id { get; set; } public string Id { get; set; }
public string Email { get; set; } public string Email { get; set; }
public string Username { get; set; } public string Username { get; set; }
public string ProfilePictureURL { get; set; } public string ProfilePicture { get; set; }
} }

View File

@ -29,6 +29,7 @@ namespace API.Persistence.Services
var request = new PutObjectRequest var request = new PutObjectRequest
{ {
InputStream = fileStream, InputStream = fileStream,
BucketName = "h4picturebucket",
Key = fileName, Key = fileName,
DisablePayloadSigning = true DisablePayloadSigning = true
}; };
@ -40,7 +41,7 @@ namespace API.Persistence.Services
throw new AmazonS3Exception($"Error uploading file to S3. HTTP Status Code: {response.HttpStatusCode}"); throw new AmazonS3Exception($"Error uploading file to S3. HTTP Status Code: {response.HttpStatusCode}");
} }
var imageUrl = $"https://pub-bf709b641048489ca70f693673e3e04c.r2.dev/{fileName}"; var imageUrl = $"https://pub-bf709b641048489ca70f693673e3e04c.r2.dev/h4picturebucket/{fileName}";
return imageUrl; return imageUrl;
} }
} }

View File

@ -1,4 +1,7 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'dart:convert'; import 'dart:convert';
@ -63,6 +66,92 @@ Future<String?> request(BuildContext? context, ApiService service, String method
return utf8.decode(response.bodyBytes); return utf8.decode(response.bodyBytes);
} }
Future<String?> putUser(
BuildContext? context,
ApiService service,
String method,
String path,
Map<String, dynamic> body,
File? profilePicture // The image file
) async {
final messenger = context != null ? ScaffoldMessenger.of(context) : null;
final prefs = await SharedPreferences.getInstance();
final host = const String.fromEnvironment('AUTH_SERVICE_HOST');
final token = prefs.getString('token');
final Map<String, String> headers = {};
if (token != null) headers.addAll({'Authorization': 'Bearer $token'});
// Create the Uri
var uri = Uri.parse(host + path);
// Create a MultipartRequest
var request = http.MultipartRequest('PUT', uri);
request.headers.addAll(headers);
// Add form fields
request.fields['id'] = body['id'];
request.fields['username'] = body['username'];
request.fields['email'] = body['email'];
request.fields['password'] = body['password'];
// Attach the file to the request (if provided)
if (profilePicture != null) {
var fileStream = http.ByteStream(profilePicture.openRead());
var length = await profilePicture.length();
var multipartFile = http.MultipartFile(
'ProfilePicture', // field name matches your backend DTO
fileStream,
length,
filename: profilePicture.path.split('/').last,
);
request.files.add(multipartFile);
}
try {
// Send the request
var streamedResponse = await request.send();
var response = await http.Response.fromStream(streamedResponse);
// Handle non-success responses
if (response.statusCode < 200 || response.statusCode >= 300) {
try {
final json = jsonDecode(response.body);
messenger?.showSnackBar(SnackBar(content: Text(json['message'] ?? json['title'])));
debugPrint('API error: ' + json['message']);
} catch (e) {
debugPrint(e.toString());
messenger?.showSnackBar(SnackBar(content: Text('Something went wrong (HTTP ${response.statusCode})')));
}
return null;
}
return utf8.decode(response.bodyBytes);
} catch (e) {
debugPrint(e.toString());
messenger?.showSnackBar(const SnackBar(content: Text('Unable to connect to server')));
return null;
}
}
Future<File> _compressImage(File file) async {
final filePath = file.absolute.path;
final lastIndex = filePath.lastIndexOf(RegExp(r'.jp'));
final splitted = filePath.substring(0, lastIndex);
final outPath = "${splitted}_compressed.jpg";
var result = await FlutterImageCompress.compressAndGetFile(
file.absolute.path,
outPath,
quality: 80,
minWidth: 1024,
minHeight: 1024,
);
return File(result!.path);
}
Future<bool> isLoggedIn(BuildContext context) async { Future<bool> isLoggedIn(BuildContext context) async {
final messenger = ScaffoldMessenger.of(context); final messenger = ScaffoldMessenger.of(context);
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();

View File

@ -1,6 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:mobile/models.dart'; import 'package:mobile/models.dart';
@ -47,48 +46,22 @@ class _ProfilePageState extends State<EditProfilePage> {
} }
Future _pickImageFromGallery() async{ Future _pickImageFromGallery() async{
final picker = ImagePicker(); final image = await ImagePicker().pickImage(source: ImageSource.gallery);
final XFile? image = await picker.pickImage(source: ImageSource.gallery); if (image == null) return;
if(image == null) {return;}
else{
File compressedFile = await _compressImage(File(image.path));
setState(() { setState(() {
_selectedImage = compressedFile; _selectedImage = File(image.path);
}); });
} }
}
Future _pickImageFromCamera() async{ Future _pickImageFromCamera() async{
final picker = ImagePicker(); final image = await ImagePicker().pickImage(source: ImageSource.camera);
final XFile? image = await picker.pickImage(source: ImageSource.camera); if (image == null) return;
if(image == null) {return;}
else{
File compressedFile = await _compressImage(File(image.path));
setState(() { setState(() {
_selectedImage = compressedFile; _selectedImage = File(image.path);
}); });
} }
}
Future<File> _compressImage(File file) async {
final filePath = file.absolute.path;
final lastIndex = filePath.lastIndexOf(RegExp(r'.jp'));
final splitted = filePath.substring(0, lastIndex);
final outPath = "${splitted}_compressed.jpg";
var result = await FlutterImageCompress.compressAndGetFile(
file.absolute.path,
outPath,
quality: 80,
minWidth: 1024,
minHeight: 1024,
);
return File(result!.path);
}
void _saveProfile() async { void _saveProfile() async {
if (passwordInput.text != confirmPasswordInput.text) { if (passwordInput.text != confirmPasswordInput.text) {
@ -100,44 +73,40 @@ class _ProfilePageState extends State<EditProfilePage> {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
String? id = prefs.getString('id'); String? id = prefs.getString('id');
if (!mounted) { if (!mounted) return;
return;
} if (id != null) {
if (id != null){ final response = await api.putUser(
final response = await api.request(context, api.ApiService.auth, 'PUT', '/api/users', { context,
'id' : id, api.ApiService.auth,
'PUT',
'/api/users',
{
'id': id,
'username': usernameInput.text, 'username': usernameInput.text,
'email': emailInput.text, 'email': emailInput.text,
'password': passwordInput.text, 'password': passwordInput.text,
'profilePicture': _selectedImage, },
}); _selectedImage // Pass the selected image to the putUser function
);
if (!mounted) { if (!mounted) return;
return;
}
if (response != null) { if (response != null) {
User updatedUser = User(
id,
emailInput.text,
usernameInput.text,
_selectedImage,
DateTime.now(),
);
setState(() { setState(() {
user = updatedUser; user = null;
}); });
Navigator.of(context).pop(); // Close the dialog Navigator.of(context).pop(); // Close the dialog
Navigator.pushReplacementNamed(context, '/profile'); Navigator.pushReplacementNamed(context, '/profile');
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Something went wrong! Please contact an admin.')), const SnackBar(content: Text('Something went wrong! Please contact an admin.')),
); );
} }
} }
} }
void _deleteProfile(BuildContext context) { void _deleteProfile(BuildContext context) {
showDialog( showDialog(

View File

@ -44,7 +44,7 @@ class User {
String id; String id;
String email; String email;
String username; String username;
File? profilePicture; String profilePicture;
DateTime createdAt; DateTime createdAt;
User( this.id, this.email, this.username, this.profilePicture, this.createdAt); User( this.id, this.email, this.username, this.profilePicture, this.createdAt);

View File

@ -41,6 +41,8 @@ class _ProfilePageState extends State<ProfilePage> {
Map<String, dynamic> json = jsonDecode(response); Map<String, dynamic> json = jsonDecode(response);
User jsonUser = User.fromJson(json); User jsonUser = User.fromJson(json);
print(jsonUser.profilePicture);
setState(() { setState(() {
userData = jsonUser; userData = jsonUser;
user = jsonUser; user = jsonUser;
@ -71,11 +73,13 @@ class _ProfilePageState extends State<ProfilePage> {
: Column( : Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
userData?.profilePicture != null ?
const Icon( const Icon(
Icons.account_circle, Icons.account_circle,
size: 100, size: 100,
color: Colors.grey, color: Colors.grey,
), )
: Image(image: NetworkImage('https://pub-bf709b641048489ca70f693673e3e04c.r2.dev/h4picturebucket/PPb83569bef3b9470782d7b42bc4e552ff.png'), height: 100),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
userData!.username, userData!.username,