This commit is contained in:
LilleBRG 2025-05-07 13:52:43 +02:00
commit dc7e94b37b
17 changed files with 266 additions and 24 deletions

View File

@ -98,7 +98,7 @@ data class UpdateUserRequest(val userName: String, val email: String)
fun updateUser(ctx: Context, username: String, email: String) {
val request = UpdateUserRequest(username, email)
return requestJson<UpdateUserRequest, Unit>(ctx, "PUT", "/api/User/update", request)
requestJson<UpdateUserRequest, Boolean>(ctx, "PUT", "/api/User/update", request)
}
@Serializable

View File

@ -0,0 +1,20 @@
package tech.mercantec.easyeat.helpers
import android.content.Context
import kotlinx.serialization.Serializable
@Serializable
data class ShoppingListItem(val id: Int, val name: String, val amount: Double?, val unit: String?, val checked: Boolean)
fun getShoppingList(ctx: Context): Array<ShoppingListItem> {
return requestJson<Unit, Array<ShoppingListItem>>(ctx, "GET", "/api/ShoppingList/get", null)
}
@Serializable
data class AddShoppingItemRequest(val name: String, val amount: Double?, val unit: String?, val checked: Boolean)
fun addShoppingItem(ctx: Context, name: String, amount: Double?, unit: String?) {
val request = AddShoppingItemRequest(name, amount, unit, false)
requestJson<AddShoppingItemRequest, Boolean>(ctx, "POST", "/api/ShoppingList/add", request)
}

View File

@ -1,6 +1,7 @@
package tech.mercantec.easyeat.ui.profile
import android.app.ProgressDialog
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
@ -43,6 +44,11 @@ class EditProfileActivity : AppCompatActivity() {
}
}
val intent = Intent()
intent.putExtra("username", username)
intent.putExtra("email", email)
setResult(RESULT_OK, intent)
finish()
}
}

View File

@ -1,11 +1,15 @@
package tech.mercantec.easyeat.ui.profile
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.children
import androidx.fragment.app.Fragment
import tech.mercantec.easyeat.ui.auth.WelcomeActivity
import tech.mercantec.easyeat.databinding.FragmentProfileBinding
@ -16,8 +20,25 @@ import tech.mercantec.easyeat.helpers.logout
import kotlin.concurrent.thread
class ProfileFragment : Fragment() {
private lateinit var launcher: ActivityResultLauncher<Intent>
private lateinit var binding: FragmentProfileBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.data == null || it.resultCode != Activity.RESULT_OK) return@registerForActivityResult
binding.username.text = it.data!!.getStringExtra("username")
binding.email.text = it.data!!.getStringExtra("email")
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val binding = FragmentProfileBinding.inflate(inflater, container, false)
binding = FragmentProfileBinding.inflate(inflater, container, false)
binding.layout.children.forEach { it.visibility = View.GONE }
binding.loading.visibility = View.VISIBLE
thread {
val userInfo: UserInfoResponse
@ -29,6 +50,11 @@ class ProfileFragment : Fragment() {
}
return@thread
} finally {
activity?.runOnUiThread {
binding.layout.children.forEach { it.visibility = View.VISIBLE }
binding.loading.visibility = View.GONE
}
}
activity?.runOnUiThread {
@ -37,9 +63,10 @@ class ProfileFragment : Fragment() {
binding.editProfile.setOnClickListener {
val intent = Intent(activity, EditProfileActivity::class.java)
intent.putExtra("username", userInfo.userName)
intent.putExtra("email", userInfo.email)
startActivity(intent)
intent.putExtra("username", binding.username.text)
intent.putExtra("email", binding.email.text)
launcher.launch(intent)
}
}
}

View File

@ -1,15 +1,21 @@
package tech.mercantec.easyeat.ui.shopping_list
import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.Spinner
import android.widget.Toast
import androidx.fragment.app.Fragment
import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.databinding.FragmentShoppingListBinding
import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.addShoppingItem
import kotlin.concurrent.thread
class ShoppingListFragment : Fragment() {
@ -32,12 +38,33 @@ class ShoppingListFragment : Fragment() {
val dialog = AlertDialog.Builder(activity)
.setView(view)
.setPositiveButton(R.string.add_label, { dialog, id ->
.setPositiveButton(R.string.add_label) { dialog, id ->
val dialog = dialog as AlertDialog
})
.setNegativeButton(R.string.cancel_label, { dialog, id ->
val amount = view.findViewById<EditText>(R.id.amount).text.toString().toDouble()
val unit = view.findViewById<Spinner>(R.id.unit_selector).selectedItem.toString().ifEmpty { null }
val name = view.findViewById<EditText>(R.id.name).text.toString()
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).isEnabled = false
thread {
try {
addShoppingItem(requireContext(), name, amount, unit)
} catch (e: ApiRequestException) {
activity?.runOnUiThread {
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
}
} finally {
activity?.runOnUiThread {
dialog.dismiss()
}
}
}
}
.setNegativeButton(R.string.cancel_label) { dialog, _ ->
dialog.cancel()
})
}
.create()
dialog.show()

View File

@ -30,12 +30,14 @@
android:layout_height="wrap_content"
android:layout_below="@id/amount_label"
android:layout_alignParentStart="true"
android:inputType="numberDecimal"
android:importantForAutofill="no"
android:hint="@string/ingredient_amount_hint"
/>
<Spinner
android:id="@+id/unit_selector"
android:layout_width="72dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/amount"
android:layout_below="@+id/amount_label"
@ -57,6 +59,8 @@
android:layout_below="@id/name_label"
android:layout_toEndOf="@id/unit_selector"
android:layout_alignParentEnd="true"
android:inputType="text"
android:importantForAutofill="no"
android:hint="@string/ingredient_name_hint"
/>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
@ -30,7 +31,6 @@
android:textSize="24sp"
android:textStyle="bold"
android:textAlignment="center"
android:text="@string/loading"
/>
<TextView
@ -40,7 +40,6 @@
android:layout_height="wrap_content"
android:textSize="18sp"
android:textAlignment="center"
android:text="@string/loading"
/>
<LinearLayout

View File

@ -39,6 +39,7 @@
<string name="change_password_label">Change password</string>
<string name="logout_label">Log out</string>
<string-array name="units">
<item></item>
<item>g</item>
<item>kg</item>
<item>ml</item>

View File

@ -16,8 +16,8 @@ namespace API.BusinessLogic
/// <summary>
/// Gets all the recipes from _dbaccess and checks if there are any
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
/// <param name="userId">the usér connected to the recipes</param>
/// <returns>a list of recipes in a ok objectresult</returns>
public async Task<IActionResult> GetRecipes(int userId)
{
var recipes = await _dbAccess.ReadRecipes(userId);
@ -26,7 +26,7 @@ namespace API.BusinessLogic
return new OkObjectResult(recipes);
}
//
// Gets a specifik with recipe with the ingredient and directions
public async Task<IActionResult> GetRecipe(int recipeId)
{
var recipe = await _dbAccess.ReadRecipe(recipeId);
@ -36,6 +36,13 @@ namespace API.BusinessLogic
return new OkObjectResult(recipe);
}
/// <summary>
/// Creates a recipe and checks if the recipe name is in use
/// Converts the recipeDTO to a normal recipe
/// </summary>
/// <param name="recipe">The recipeDTO that does not include all the id tags</param>
/// <param name="userId">The user that is going to get that recipe</param>
/// <returns>returns what recipedbaccess gives back</returns>
public async Task<IActionResult> CreateRecipe(RecipeDTO recipe, int userId)
{
var recipes = await _dbAccess.ReadRecipes(userId);
@ -71,6 +78,13 @@ namespace API.BusinessLogic
return await _dbAccess.CreateRecipe(dish, userId);
}
/// <summary>
/// Updates the recipe that is saved in the db
/// </summary>
/// <param name="recipe">The updated recipe</param>
/// <param name="recipeId">The recipeId on the recipe to be updated</param>
/// <param name="userId">The userÍd of the owner of the to be updated recipe</param>
/// <returns>returns what recipedbaccess gives back</returns>
public async Task<IActionResult> EditRecipe(RecipeDTO recipe, int recipeId, int userId)
{
var recipes = await _dbAccess.ReadRecipes(userId);
@ -105,13 +119,14 @@ namespace API.BusinessLogic
return await _dbAccess.UpdateRecipe(dish);
}
// Deletes the recipe
public async Task<IActionResult> DeleteRecipe(int recipeId)
{
var recipe = await _dbAccess.ReadRecipe(recipeId);
if (recipe != null) { return await _dbAccess.DeleteUser(recipe); }
if (recipe != null) { return await _dbAccess.DeleteRecipe(recipe); }
return new ConflictObjectResult(new { message = "Invalid user" });
return new ConflictObjectResult(new { message = "Invalid recipe" });
}
}
}

View File

@ -15,6 +15,7 @@ namespace API.BusinessLogic
_recipeDBAccess = recipeDBAccess;
}
// Reads the current shooping list of the user
public async Task<IActionResult> ReadShoppingList(int userId)
{
var user = await _dbAccess.ReadShoppingList(userId);
@ -22,6 +23,7 @@ namespace API.BusinessLogic
return new OkObjectResult(user.ShoppingList);
}
// Adds an item to the shoppinglist and checks if the unit should be changed and if the name is the same as an item already on the shoppinglist
public async Task<IActionResult> AddItemToShoppingList(ShoppingListItemDTO listItemDTO, int userId)
{
var user = await _dbAccess.ReadShoppingList(userId);
@ -42,12 +44,12 @@ namespace API.BusinessLogic
item.Amount = (item.Amount / 1000) + listItemDTO.Amount;
item.Unit = "kg";
}
else if (item.Unit == "ml" && item.Unit == "l")
else if (item.Unit == "ml" && listItemDTO.Unit == "l")
{
item.Amount = (item.Amount / 1000) + listItemDTO.Amount;
item.Unit = "l";
}
else if (item.Unit == "dl" && item.Unit == "l")
else if (item.Unit == "dl" && listItemDTO.Unit == "l")
{
item.Amount = (item.Amount / 10) + listItemDTO.Amount;
item.Unit = "l";
@ -85,6 +87,7 @@ namespace API.BusinessLogic
return await _dbAccess.UpdateShoppingList(user);
}
// Gets the shoppinglist and tries to find the item and when it does it checks/unchecks that item
public async Task<IActionResult> CheckItemInShoppingList(int userId, int itemId)
{
var user = await _dbAccess.ReadShoppingList(userId);
@ -96,6 +99,7 @@ namespace API.BusinessLogic
return await _dbAccess.UpdateShoppingList(user);
}
// Updates an item on the shopping list to what the user specified
public async Task<IActionResult> UpdateItemInShoppingList(int userId, int itemId, ShoppingListItemDTO listItemDTO)
{
var user = await _dbAccess.ReadShoppingList(userId);
@ -125,6 +129,7 @@ namespace API.BusinessLogic
return await _dbAccess.UpdateShoppingList(user);
}
// Deletes an item from the shopping list if it is on the users shoppinglist
public async Task<IActionResult> DeleteItemInShoppingList(int userId, int itemId)
{
var user = await _dbAccess.ReadShoppingList(userId);
@ -136,6 +141,7 @@ namespace API.BusinessLogic
return await _dbAccess.UpdateShoppingList(user);
}
// Adds an entire recipes ingredients to the shoppinglist
public async Task<IActionResult> AddRecipeToShoppingList(int userId, int recipeId)
{
var user = await _dbAccess.ReadShoppingList(userId);

View File

@ -23,6 +23,7 @@ namespace API.BusinessLogic
_configuration = configuration;
}
// Gets an user from their id
public async Task<IActionResult> GetUser(int userId)
{
User user = await _dbAccess.ReadUser(userId);
@ -31,6 +32,7 @@ namespace API.BusinessLogic
return new OkObjectResult(new { user.Id, user.UserName, user.Email });
}
// Checks if the userdata is ok before the user is created and creats the othere list's that the user have
public async Task<IActionResult> RegisterUser(CreateUserDTO userDTO)
{
if (!EmailCheck(userDTO.Email))
@ -71,6 +73,7 @@ namespace API.BusinessLogic
return await _dbAccess.CreateUser(user);
}
// Checks if the username/email matches the password and generates a jwttoken if it is correct
public async Task<IActionResult> Login(LoginDTO loginDTO)
{
var user = await _dbAccess.ReadUserForLogin(loginDTO.EmailUsr);
@ -91,6 +94,7 @@ namespace API.BusinessLogic
return new ConflictObjectResult(new { message = "Invalid password" });
}
// Checks if the username or email is already in use and changes them if they are diffrent from before
public async Task<IActionResult> EditProfile(UpdateUserDTO userDTO, int userId)
{
var profile = await _dbAccess.ReadUser(userId);
@ -142,6 +146,7 @@ namespace API.BusinessLogic
return await _dbAccess.UpdateUser(profile);
}
// Checks if the old password is correct and then it checks if the password is secure enough
public async Task<IActionResult> ChangePassword(ChangePasswordDTO passwordDTO, int userId)
{
var user = await _dbAccess.ReadUser(userId);
@ -167,6 +172,7 @@ namespace API.BusinessLogic
return await _dbAccess.UpdatePassword(user);
}
// Checks if the user exist and it deletes that user
public async Task<IActionResult> DeleteUser(int userId)
{
var user = await _dbAccess.ReadUserForDelete(userId);
@ -176,6 +182,7 @@ namespace API.BusinessLogic
return new ConflictObjectResult(new { message = "Invalid user" });
}
// Checks if the refreshtoken is correct and if it is it generates a new jwttoken and refreshtoken
public async Task<IActionResult> RefreshToken(string refreshToken)
{
User user = await _dbAccess.ReadUserByRefreshToken(refreshToken);
@ -185,6 +192,7 @@ namespace API.BusinessLogic
return new OkObjectResult(new { token = jwtToken, refreshToken = user.RefreshToken });
}
// Checks if the password is up to our security standard
private bool PasswordSecurity(string password)
{
var hasMinimum8Chars = new Regex(@".{8,}");
@ -192,11 +200,19 @@ namespace API.BusinessLogic
return hasMinimum8Chars.IsMatch(password);
}
// Checks if the email has all the things an email should have
private bool EmailCheck(string email)
{
return new Regex(@".+@.+\..+").IsMatch(email);
}
/// <summary>
/// Generates a hash from a salt and input using the algorithm that is provided
/// </summary>
/// <param name="input">This is the input that is supposed to be hashed</param>
/// <param name="algorithm">This is the alogorithm that is used to encrypt the input</param>
/// <param name="salt">This is something extra added to make the hashed input more unpredictable</param>
/// <returns>The hashed input</returns>
private static string ComputeHash(string input, HashAlgorithm algorithm, string salt)
{
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
@ -212,6 +228,7 @@ namespace API.BusinessLogic
return BitConverter.ToString(hashedBytes);
}
// Generates a jwttoken that contains the users id and username and a unique identifier that is valid for 1 hour
private string GenerateJwtToken(User user)
{
var claims = new[]
@ -235,6 +252,7 @@ namespace API.BusinessLogic
return new JwtSecurityTokenHandler().WriteToken(token);
}
// Generate a new refreshtoken that expire after 30 days
private async Task<User> UpdateRefreshToken(User user)
{
user.RefreshToken = Guid.NewGuid().ToString();

View File

@ -20,6 +20,10 @@ namespace API.Controllers
_openAiRecipes = openAiRecipes;
}
/// <summary>
/// Gets the userId from the jwt token amd returns a list of recipes without their ingredients and directions
/// </summary>
/// <returns>returns a okobjectresult with a list of recipes if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpGet("getall")]
public async Task<IActionResult> ReadRecipes()
@ -30,6 +34,11 @@ namespace API.Controllers
return await _recipeLogic.GetRecipes(userId);
}
/// <summary>
/// Gets a specifik recipe including the ingredients and directions
/// </summary>
/// <param name="recipeId">The recipe that is you want</param>
/// <returns>returns a okobjectresult with a recipe if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpGet("get/{recipeId}")]
public async Task<IActionResult> ReadRecipe(int recipeId)
@ -37,6 +46,11 @@ namespace API.Controllers
return await _recipeLogic.GetRecipe(recipeId);
}
/// <summary>
/// Creates a recipe and adds it to the users recipes
/// </summary>
/// <param name="recipe">The recipe to be added</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpPost("create")]
public async Task<IActionResult> CreateRecipe([FromBody] RecipeDTO recipe)
@ -47,6 +61,12 @@ namespace API.Controllers
return await _recipeLogic.CreateRecipe(recipe, userId);
}
/// <summary>
/// Edits a recipe
/// </summary>
/// <param name="recipe">the edited recipe</param>
/// <param name="recipeId">the recipe to be edited</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpPut("edit/{recipeId}")]
public async Task<IActionResult> EditRecipe([FromBody] RecipeDTO recipe, int recipeId)
@ -57,6 +77,11 @@ namespace API.Controllers
return await _recipeLogic.EditRecipe(recipe, recipeId, userId);
}
/// <summary>
/// Deletess a recipe
/// </summary>
/// <param name="recipeId">the id of the recipe to be deleted</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpDelete("delete/{recipeId}")]
public async Task<IActionResult> DeleteRecipe(int recipeId)
@ -64,6 +89,11 @@ namespace API.Controllers
return await _recipeLogic.DeleteRecipe(recipeId);
}
/// <summary>
/// Generates a recipe using chatgpt
/// </summary>
/// <param name="recipeDTO">Contains all the infomation that is needed to generate a recipe</param>
/// <returns>returns a list of generated recipes</returns>
[Authorize]
[HttpPost("chatbot")]
public async Task<IActionResult> GenerateRecipe([FromBody] GenerateRecipeDTO recipeDTO)

View File

@ -1,6 +1,7 @@

using API.BusinessLogic;
using API.Models.ShoppingListModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
@ -17,6 +18,11 @@ namespace API.Controllers
_shoppingListLogic = shoppingListLogic;
}
/// <summary>
/// Gets the entire shoppinglist connected to the user
/// </summary>
/// <returns>returns a list of shoppinglist items if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpGet("get")]
public async Task<IActionResult> ReadShoppingList()
{
@ -26,6 +32,12 @@ namespace API.Controllers
return await _shoppingListLogic.ReadShoppingList(userId);
}
/// <summary>
/// Adds an item to the shopping list
/// </summary>
/// <param name="listItemDTO"></param>
/// <returns></returns>
[Authorize]
[HttpPost("add")]
public async Task<IActionResult> AddItem([FromBody] ShoppingListItemDTO listItemDTO)
{
@ -35,6 +47,12 @@ namespace API.Controllers
return await _shoppingListLogic.AddItemToShoppingList(listItemDTO, userId);
}
/// <summary>
/// Checks/Unchecks an item on the shoppinglist
/// </summary>
/// <param name="itemId">The item to be checked/unchecked</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpPut("check")]
public async Task<IActionResult> CheckItem(int itemId)
{
@ -44,6 +62,13 @@ namespace API.Controllers
return await _shoppingListLogic.CheckItemInShoppingList(userId, itemId);
}
/// <summary>
/// Edits an item on the shoppinglist
/// </summary>
/// <param name="listItemDTO">The edited item</param>
/// <param name="itemId">The item to be edited</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpPut("update")]
public async Task<IActionResult> UpdateItem([FromBody] ShoppingListItemDTO listItemDTO, int itemId)
{
@ -53,6 +78,12 @@ namespace API.Controllers
return await _shoppingListLogic.UpdateItemInShoppingList(userId, itemId, listItemDTO);
}
/// <summary>
/// Deletes an item on the shoppinglist
/// </summary>
/// <param name="itemId">The item to be deleted</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpDelete("delete")]
public async Task<IActionResult> DeleteItem(int itemId)
{
@ -62,6 +93,12 @@ namespace API.Controllers
return await _shoppingListLogic.DeleteItemInShoppingList(userId, itemId);
}
/// <summary>
/// Add an entire recipes ingredients to the shoppinglist
/// </summary>
/// <param name="recipeId">The recipes ingredients to be added</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpPost("recipeadd")]
public async Task<IActionResult> AddARecipesItems(int recipeId)
{

View File

@ -17,6 +17,10 @@ namespace API.Controllers
_userLogic = userLogic;
}
/// <summary>
/// Gets the users email and username
/// </summary>
/// <returns>returns the users email, username and Id</returns>
[Authorize]
[HttpGet("get")]
public async Task<IActionResult> ReadUser()
@ -27,18 +31,33 @@ namespace API.Controllers
return await _userLogic.GetUser(userId);
}
/// <summary>
/// Logins a user
/// </summary>
/// <param name="loginDTO">The users login credentials</param>
/// <returns>Returns a jwttoken their username, id and a refreshtoken</returns>
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginDTO loginDTO)
{
return await _userLogic.Login(loginDTO);
}
/// <summary>
/// Create a new user
/// </summary>
/// <param name="userDTO">contains the username email and password</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[HttpPost("create")]
public async Task<IActionResult> CreateUser([FromBody] CreateUserDTO userDTO)
{
return await _userLogic.RegisterUser(userDTO);
}
/// <summary>
/// Changes the password of the user
/// </summary>
/// <param name="passwordDTO">Contains the old password and the new one</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpPut("change-password")]
public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordDTO passwordDTO)
@ -49,6 +68,11 @@ namespace API.Controllers
return await _userLogic.ChangePassword(passwordDTO, userId);
}
/// <summary>
/// Edits the email and username of the user
/// </summary>
/// <param name="userDTO">The updated username and email</param>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpPut("update")]
public async Task<IActionResult> UpdateUser([FromBody] UpdateUserDTO userDTO)
@ -59,6 +83,10 @@ namespace API.Controllers
return await _userLogic.EditProfile(userDTO, userId);
}
/// <summary>
/// Deletes the user
/// </summary>
/// <returns>returns a okobjectresult with a boolean that is true if it fails it returns a confliftobjectresult with a message of why it failed</returns>
[Authorize]
[HttpDelete("delete")]
public async Task<IActionResult> DeleteUser()
@ -69,6 +97,11 @@ namespace API.Controllers
return await _userLogic.DeleteUser(userId);
}
/// <summary>
/// For when the jwt token is outdated
/// </summary>
/// <param name="refreshToken">contains a string with the refreshtoken</param>
/// <returns>returns a new refreshtoken and new jwt token</returns>
[HttpPost("refreshtoken")]
public async Task<IActionResult> RefreashToken([FromBody] RefreshTokenDTO refreshToken)
{

View File

@ -14,6 +14,7 @@ namespace API.DBAccess
_context = context;
}
// Reads the users recipes
public async Task<List<Recipe>> ReadRecipes(int userId)
{
var recipes = await _context.Users.Include(p => p.Recipes).FirstOrDefaultAsync(u => u.Id == userId);
@ -21,11 +22,13 @@ namespace API.DBAccess
return recipes.Recipes;
}
// Returns a specifik recipe
public async Task<Recipe> ReadRecipe(int recipeId)
{
return await _context.Recipes.Include(r => r.Ingredients).FirstOrDefaultAsync(r => r.Id == recipeId);
return await _context.Recipes.Include(r => r.Ingredients).Include(r => r.Directions).FirstOrDefaultAsync(r => r.Id == recipeId);
}
// Adds a new recipe to the database
public async Task<IActionResult> CreateRecipe(Recipe recipe, int userId)
{
var recipes = await _context.Users.Include(p => p.Recipes).FirstOrDefaultAsync(u => u.Id == userId);
@ -39,6 +42,7 @@ namespace API.DBAccess
return new ConflictObjectResult(new { message = "Could not save to database" });
}
// Updates the recipe in the database
public async Task<IActionResult> UpdateRecipe(Recipe recipe)
{
_context.Entry(recipe).State = EntityState.Modified;
@ -50,7 +54,8 @@ namespace API.DBAccess
return new ConflictObjectResult(new { message = "Could not save to database" });
}
public async Task<IActionResult> DeleteUser(Recipe recipe)
// Deletes the recipe from the database
public async Task<IActionResult> DeleteRecipe(Recipe recipe)
{
_context.Recipes.Remove(recipe);
bool saved = await _context.SaveChangesAsync() >= 0;

View File

@ -14,6 +14,8 @@ namespace API.DBAccess
{
_context = context;
}
// Read the shoppinglist connected to the user
public async Task<User> ReadShoppingList(int userId)
{
var user = await _context.Users.Include(u => u.ShoppingList).FirstOrDefaultAsync(u => u.Id == userId);
@ -21,13 +23,14 @@ namespace API.DBAccess
return user;
}
// Updates the shoppinglist
public async Task<IActionResult> UpdateShoppingList(User user)
{
_context.Entry(user).State = EntityState.Modified;
bool saved = await _context.SaveChangesAsync() >= 1;
if (saved) { return new OkObjectResult(user); }
if (saved) { return new OkObjectResult(true); }
return new ConflictObjectResult(new { message = "Could not save to database" });
}

View File

@ -13,16 +13,19 @@ namespace API.DBAccess
_context = context;
}
// Reads the user from the database
public async Task<User> ReadUser(int userId)
{
return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);
}
// Reads all the users from the database
public async Task<List<User>> ReadAllUsers()
{
return await _context.Users.ToListAsync();
}
// Searches for a user with the username
public async Task<bool> UserNameInUse(string username)
{
var user = await _context.Users.FirstOrDefaultAsync(u => u.UserName == username);
@ -30,6 +33,7 @@ namespace API.DBAccess
return true;
}
// Searches for a user with the email
public async Task<bool> EmailInUse(string email)
{
var user = await _context.Users.FirstOrDefaultAsync(u => u.UserName == email);
@ -37,16 +41,19 @@ namespace API.DBAccess
return true;
}
// Searches for a user with refreshtoken and returns that user
public async Task<User> ReadUserByRefreshToken(string refreshToken)
{
return await _context.Users.FirstOrDefaultAsync(u => u.RefreshToken == refreshToken);
}
// Gets all the data for a user
public async Task<User> ReadUserForDelete(int userId)
{
return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);
return await _context.Users.Include(u => u.Recipes).ThenInclude(r => r.Ingredients).Include(u => u.Recipes).ThenInclude(r => r.Directions).Include(u => u.ShoppingList).FirstOrDefaultAsync(u => u.Id == userId);
}
// Gets a user according to either the email or username
public async Task<User> ReadUserForLogin(string emailOrUsername)
{
if (emailOrUsername.Contains("@"))
@ -59,6 +66,7 @@ namespace API.DBAccess
}
}
// Adds a new user to the database
public async Task<IActionResult> CreateUser(User user)
{
_context.Users.Add(user);
@ -71,17 +79,19 @@ namespace API.DBAccess
}
// Updates the user in the database
public async Task<IActionResult> UpdateUser(User user)
{
_context.Entry(user).State = EntityState.Modified;
bool saved = await _context.SaveChangesAsync() == 1;
if (saved) { return new OkObjectResult(user); }
if (saved) { return new OkObjectResult(true); }
return new ConflictObjectResult(new { message = "Could not save to database" });
}
// Updates the password in the database
public async Task<IActionResult> UpdatePassword(User user)
{
_context.Entry(user).State = EntityState.Modified;
@ -93,6 +103,7 @@ namespace API.DBAccess
return new ConflictObjectResult(new { message = "Could not save to database" });
}
// Deletes the user from the database
public async Task<IActionResult> DeleteUser(User user)
{
_context.Users.Remove(user);