Refactoring: Added interfaces, custom exceptions, UserManager unit tests, dependency injection/inversion; Regex match search by date, keywords

This commit is contained in:
Dimitar Byalkov
2023-06-06 17:52:36 +02:00
parent 180b261d37
commit 53c42a35d8
43 changed files with 668 additions and 211 deletions

View File

@@ -1,14 +1,17 @@
using Models; using Models;
using Logic;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Logic.Exceptions;
using System.Reflection;
namespace Data namespace Data
{ {
public class AnnouncementRepository public class AnnouncementRepository : IAnnouncementRepository
{ {
public AnnouncementRepository() { } public AnnouncementRepository() { }
public List<Announcement> GetAllAnnouncements() public List<Announcement> GetAllAnnouncements()
@@ -58,21 +61,21 @@ namespace Data
return announcement; return announcement;
} }
} }
public List<Announcement> GetAnnouncementsByPage(int? p, int? c) public List<Announcement> GetAnnouncementsByPage(int p, int c)
{ {
List<Announcement> announcements = new List<Announcement>(); List<Announcement> announcements = new List<Announcement>();
UserRepository userRepository = new UserRepository(); UserRepository userRepository = new UserRepository();
if (c == null || c < 0) if (c == null)
{ {
c = 10; throw new DatabaseOperationException("Get announcements: Invalid item count");
} }
if (p == null || p < 0) if (p == null)
{ {
p = 0; throw new DatabaseOperationException("Get announcements: Invalid page number");
} }
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
string sql = "SELECT * FROM Announcements ORDER BY ID OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;"; string sql = "SELECT * FROM Announcements ORDER BY ID DESC OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;";
SqlCommand sqlCommand = new SqlCommand(sql, conn); SqlCommand sqlCommand = new SqlCommand(sql, conn);
sqlCommand.Parameters.AddWithValue("@start", p * c); sqlCommand.Parameters.AddWithValue("@start", p * c);
sqlCommand.Parameters.AddWithValue("@count", c); sqlCommand.Parameters.AddWithValue("@count", c);
@@ -89,7 +92,7 @@ namespace Data
} }
return announcements; return announcements;
} }
public bool CreateAnnouncement(string title, string description, User author, DateTime publishDate, bool isImportant, bool isSticky) public void CreateAnnouncement(string title, string description, User author, DateTime publishDate, bool isImportant, bool isSticky)
{ {
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
@@ -102,15 +105,13 @@ namespace Data
cmd.Parameters.AddWithValue("@important", isImportant); cmd.Parameters.AddWithValue("@important", isImportant);
cmd.Parameters.AddWithValue("@sticky", isSticky); cmd.Parameters.AddWithValue("@sticky", isSticky);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
if (writer == 1)
{ {
return true; throw new DatabaseOperationException("Database error: Announcement not created");
} }
else return false;
} }
} }
public bool UpdateAnnouncement(int id, string title, string description, bool isImportant, bool isSticky) public void UpdateAnnouncement(int id, string title, string description, bool isImportant, bool isSticky)
{ {
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
@@ -124,15 +125,13 @@ namespace Data
cmd.Parameters.AddWithValue("@sticky", isSticky); cmd.Parameters.AddWithValue("@sticky", isSticky);
cmd.Parameters.AddWithValue("@id", id); cmd.Parameters.AddWithValue("@id", id);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
if (writer == 1)
{ {
return true; throw new DatabaseOperationException("Database error: Announcement not updated");
} }
else return false;
} }
} }
public bool DeleteAnnouncement(int id) public void DeleteAnnouncement(int id)
{ {
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
@@ -140,13 +139,54 @@ namespace Data
SqlCommand cmd = new SqlCommand(sql, conn); SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@id", id); cmd.Parameters.AddWithValue("@id", id);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
if (writer == 1)
{ {
return true; throw new DatabaseOperationException("Database error: Announcement not deleted");
} }
else return false;
} }
} }
public List<Announcement> SearchAnnouncement(string query)
{
if (string.IsNullOrEmpty(query))
{
throw new DatabaseOperationException("Search announements error: Search query is empty");
}
List<Announcement> announcements = new List<Announcement>();
UserRepository userRepository = new UserRepository();
StringBuilder sql = new StringBuilder();
sql.Append("SELECT * FROM Announcements ");
string[] searchStrings = query.Trim().Split(' ');
for (int i = 0; i < searchStrings.Length; i++)
{
if (i == 0)
{
sql.Append($"WHERE Title LIKE @query{i} OR Description LIKE @query{i} ");
}
else
{
sql.Append($"OR Title LIKE @query{i} OR Description LIKE @query{i} ");
}
}
sql.Append(';');
using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{
SqlCommand sqlCommand = new SqlCommand(sql.ToString(), conn);
for (int i = 0; i < searchStrings.Length; i++)
{
sqlCommand.Parameters.AddWithValue($"@query{i}", $"%{searchStrings[i]}%");
}
var reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
announcements.Add(new Announcement(Convert.ToInt32(reader["ID"]),
userRepository.GetUserById(Convert.ToInt32(reader["Author"])),
reader["Description"].ToString(), reader["Title"].ToString(),
(DateTime)reader["PublishDate"], (bool)reader["IsImportant"],
(bool)reader["IsSticky"]));
}
}
return announcements;
}
} }
} }

View File

@@ -1,10 +1,12 @@
using System.ComponentModel.Design; using System.ComponentModel.Design;
using System.Data.SqlClient; using System.Data.SqlClient;
using Models; using Models;
using Logic;
using Logic.Exceptions;
namespace Data; namespace Data;
public class CommentRepository public class CommentRepository : ICommentRepository
{ {
public CommentRepository() public CommentRepository()
{ {
@@ -100,10 +102,14 @@ public class CommentRepository
cmd.Parameters.AddWithValue("@desc", description); cmd.Parameters.AddWithValue("@desc", description);
cmd.Parameters.AddWithValue("@id", id); cmd.Parameters.AddWithValue("@id", id);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
{
throw new DatabaseOperationException("Database error: Comment not updated");
}
} }
} }
private Comment CreateComment(User author, string description, string title, DateTime publishDate) public Comment CreateComment(User author, string description, string title, DateTime publishDate)
{ {
using (SqlConnection connection = SqlConnectionHelper.CreateConnection()) using (SqlConnection connection = SqlConnectionHelper.CreateConnection())
{ {
@@ -128,6 +134,10 @@ public class CommentRepository
cmd.Parameters.AddWithValue("@announcementID", announcementId); cmd.Parameters.AddWithValue("@announcementID", announcementId);
cmd.Parameters.AddWithValue("@commentID", comment.ID); cmd.Parameters.AddWithValue("@commentID", comment.ID);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
{
throw new DatabaseOperationException("Database error: Announcement comment not created");
}
} }
} }
public void CreateResponseOnComment(User author, string description, string title, DateTime publishDate, int commentId) public void CreateResponseOnComment(User author, string description, string title, DateTime publishDate, int commentId)
@@ -140,10 +150,14 @@ public class CommentRepository
cmd.Parameters.AddWithValue("@commentID", commentId); cmd.Parameters.AddWithValue("@commentID", commentId);
cmd.Parameters.AddWithValue("@responseID", response.ID); cmd.Parameters.AddWithValue("@responseID", response.ID);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
{
throw new DatabaseOperationException("Database error: Comment response not created");
}
} }
} }
private void DeleteComment(int id) public void DeleteComment(int id)
{ {
using (SqlConnection connection = SqlConnectionHelper.CreateConnection()) using (SqlConnection connection = SqlConnectionHelper.CreateConnection())
{ {
@@ -152,6 +166,10 @@ public class CommentRepository
SqlCommand cmd = new SqlCommand(sql, connection); SqlCommand cmd = new SqlCommand(sql, connection);
cmd.Parameters.AddWithValue("@id", id); cmd.Parameters.AddWithValue("@id", id);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
{
throw new DatabaseOperationException("Database error: Comment not deleted");
}
} }
} }
@@ -165,6 +183,10 @@ public class CommentRepository
cmd.Parameters.AddWithValue("@commentId", commentId); cmd.Parameters.AddWithValue("@commentId", commentId);
cmd.Parameters.AddWithValue("@announcementId", announcementId); cmd.Parameters.AddWithValue("@announcementId", announcementId);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
{
throw new DatabaseOperationException("Database error: Announcement comment not deleted");
}
} }
DeleteComment(commentId); DeleteComment(commentId);
} }
@@ -178,6 +200,10 @@ public class CommentRepository
cmd.Parameters.AddWithValue("@commentId", commentId); cmd.Parameters.AddWithValue("@commentId", commentId);
cmd.Parameters.AddWithValue("@responseId", responseId); cmd.Parameters.AddWithValue("@responseId", responseId);
int writer = cmd.ExecuteNonQuery(); int writer = cmd.ExecuteNonQuery();
if (writer != 1)
{
throw new DatabaseOperationException("Database error: Announcement not created");
}
} }
DeleteComment(commentId); DeleteComment(commentId);
} }

View File

@@ -11,6 +11,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Logic\Logic.csproj" />
<ProjectReference Include="..\Models\Models.csproj" /> <ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -1,4 +1,5 @@
using System; using Logic.Exceptions;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Linq; using System.Linq;
@@ -20,7 +21,6 @@ namespace Data
catch (SqlException e) catch (SqlException e)
{ {
throw new DatabaseNetworkException("Unable to access FHICT VDI database", e); throw new DatabaseNetworkException("Unable to access FHICT VDI database", e);
// Console.WriteLine("Database connection error. Are you connected to the VDI VPN?");
} }
return connection; return connection;

View File

@@ -7,10 +7,11 @@ using System.Data.SqlClient;
using Models; using Models;
using System.Data; using System.Data;
using System.Xml.Linq; using System.Xml.Linq;
using Logic;
namespace Data namespace Data
{ {
public class UserRepository public class UserRepository : IUserRepository
{ {
public UserRepository() { } public UserRepository() { }
public List<User> GetAllUsers() public List<User> GetAllUsers()
@@ -54,17 +55,9 @@ namespace Data
(UserRole)reader["Role"]); (UserRole)reader["Role"]);
} }
} }
public List<User> GetUsersByPage(int? p, int? c) public List<User> GetUsersByPage(int p, int c)
{ {
List<User> users = new List<User>(); List<User> users = new List<User>();
if (c == null || c < 0)
{
c = 10;
}
if (p == null || p < 0)
{
p = 0;
}
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
string sql = "SELECT * FROM Users ORDER BY ID OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;"; string sql = "SELECT * FROM Users ORDER BY ID OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;";
@@ -81,25 +74,20 @@ namespace Data
} }
return users; return users;
} }
public bool CreateUser(string name, string password, UserRole role) public User CreateUser(string name, string password, UserRole role)
{ {
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
string sql = "INSERT INTO Users (Name, Password, Role) VALUES (@name, @pass, @role);"; string sql = "INSERT INTO Users (Name, Password, Role) VALUES (@name, @pass, @role) " +
"SELECT SCOPE_IDENTITY();";
SqlCommand cmd = new SqlCommand(sql, conn); SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@name", name); cmd.Parameters.AddWithValue("@name", name);
cmd.Parameters.AddWithValue("@pass", password); cmd.Parameters.AddWithValue("@pass", password);
cmd.Parameters.AddWithValue("@role", (int)role); cmd.Parameters.AddWithValue("@role", (int)role);
int writer = cmd.ExecuteNonQuery(); return GetUserById(Convert.ToInt32(cmd.ExecuteScalar()));
if (writer == 1)
{
return true;
}
else return false;
} }
} }
public bool UpdateUser(int id, string name, string password, UserRole role) public void UpdateUser(int id, string name, string password, UserRole role)
{ {
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
@@ -111,16 +99,10 @@ namespace Data
cmd.Parameters.AddWithValue("@pass", password); cmd.Parameters.AddWithValue("@pass", password);
cmd.Parameters.AddWithValue("@role", (int)role); cmd.Parameters.AddWithValue("@role", (int)role);
cmd.Parameters.AddWithValue("@id", id); cmd.Parameters.AddWithValue("@id", id);
int writer = cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
if (writer == 1)
{
return true;
}
else return false;
} }
} }
public bool DisableUser(int id) public void DisableUser(int id)
{ {
using (SqlConnection conn = SqlConnectionHelper.CreateConnection()) using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
{ {
@@ -129,13 +111,21 @@ namespace Data
"WHERE ID = @id;"; "WHERE ID = @id;";
SqlCommand cmd = new SqlCommand(sql, conn); SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@id", id.ToString()); cmd.Parameters.AddWithValue("@id", id.ToString());
int writer = cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
}
}
if (writer == 1) public User GetUserByName(string userName)
{ {
return true; using (SqlConnection conn = SqlConnectionHelper.CreateConnection())
} {
else return false; string sql = "SELECT * FROM Users WHERE Name = @userName;";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@userName", userName);
var reader = cmd.ExecuteReader();
return new User(Convert.ToInt32(reader["ID"]), reader["Name"].ToString(),
reader["Password"].ToString(), (UserRole)reader["Role"]);
} }
} }
} }

View File

@@ -1,20 +1,20 @@
using Models; using Models;
using Data;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Logic namespace Logic
{ {
public class AnnouncementManager public class AnnouncementManager
{ {
private AnnouncementRepository announcementRepository; private IAnnouncementRepository announcementRepository;
public AnnouncementManager() public AnnouncementManager(IAnnouncementRepository announcementRepository)
{ {
announcementRepository = new AnnouncementRepository(); this.announcementRepository = announcementRepository;
} }
public List<Announcement> GetAllAnnouncements() public List<Announcement> GetAllAnnouncements()
{ {
@@ -24,22 +24,44 @@ namespace Logic
{ {
return announcementRepository.GetAnnouncementById(id); return announcementRepository.GetAnnouncementById(id);
} }
public List<Announcement> GetAnnouncementsByPage(int? p, int? c) public List<Announcement> GetAnnouncementsByPage(int p = 0, int c = 10)
{ {
return announcementRepository.GetAnnouncementsByPage(p, c); return announcementRepository.GetAnnouncementsByPage(p, c);
} }
public bool CreateAnnouncement(string title, string description, User author, DateTime publishDate, bool isImportant, bool isSticky) public void CreateAnnouncement(string title, string description, User author, DateTime publishDate, bool isImportant, bool isSticky)
{ {
return announcementRepository.CreateAnnouncement(title, description, author, publishDate, isImportant, isSticky); announcementRepository.CreateAnnouncement(title, description, author, publishDate, isImportant, isSticky);
} }
public bool UpdateAnnouncement(int id, string title, string description, bool isImportant, bool isSticky) public void UpdateAnnouncement(int id, string title, string description, bool isImportant, bool isSticky)
{ {
description += $"{Environment.NewLine}{Environment.NewLine}Updated: {DateTime.Now.ToString("g")}"; description += $"{Environment.NewLine}{Environment.NewLine}Updated: {DateTime.Now.ToString("g")}";
return announcementRepository.UpdateAnnouncement(id, title, description, isImportant, isSticky); announcementRepository.UpdateAnnouncement(id, title, description, isImportant, isSticky);
} }
public bool DeleteAnnouncement(int id) public void DeleteAnnouncement(int id)
{ {
return announcementRepository.DeleteAnnouncement(id); announcementRepository.DeleteAnnouncement(id);
}
public List<Announcement> SearchAnnouncements(string query)
{
if (string.IsNullOrEmpty(query))
{
return new List<Announcement>();
}
else
{
var match = Regex.Match(query, "(?<=date:)[0-9]{4}-[0-9]{2}-[0-9]{2}");
DateTime date;
if (DateTime.TryParse(match.Groups[0].Value, out date))
{
query = Regex.Replace(query, "date:[0-9]{4}-[0-9]{2}-[0-9]{2}", "");
if (string.IsNullOrEmpty(query))
{
return announcementRepository.GetAllAnnouncements().Where(x => x.PublishDate.Date == date.Date).ToList();
}
else return announcementRepository.SearchAnnouncement(query).Where(x => x.PublishDate.Date == date.Date).ToList();
}
else return announcementRepository.SearchAnnouncement(query);
}
} }
} }
} }

View File

@@ -1,5 +1,4 @@
using Models; using Models;
using Data;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -10,10 +9,10 @@ namespace Logic
{ {
public class CommentManager public class CommentManager
{ {
private CommentRepository commentRepository; private ICommentRepository commentRepository;
public CommentManager() public CommentManager(ICommentRepository commentRepository)
{ {
commentRepository = new CommentRepository(); this.commentRepository = commentRepository;
} }
public void CreateCommentToAnnouncement(User author, string description, string title, DateTime publishDate, int announcementId) public void CreateCommentToAnnouncement(User author, string description, string title, DateTime publishDate, int announcementId)

View File

@@ -5,7 +5,7 @@ using System.Net;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Data namespace Logic.Exceptions
{ {
public class DatabaseNetworkException : WebException public class DatabaseNetworkException : WebException
{ {

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Logic.Exceptions
{
public class DatabaseOperationException : ApplicationException
{
public DatabaseOperationException(string? message) : base(message)
{
}
public DatabaseOperationException(string? message, Exception? innerException) : base(message, innerException)
{
}
}
}

View File

@@ -0,0 +1,21 @@
using Models;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Logic
{
public interface IAnnouncementRepository
{
public List<Announcement> GetAllAnnouncements();
public Announcement GetAnnouncementById(int id);
public List<Announcement> GetAnnouncementsByPage(int p, int c);
public void CreateAnnouncement(string title, string description, User author, DateTime publishDate, bool isImportant, bool isSticky);
public void UpdateAnnouncement(int id, string title, string description, bool isImportant, bool isSticky);
public void DeleteAnnouncement(int id);
public List<Announcement> SearchAnnouncement(string query);
}
}

View File

@@ -0,0 +1,19 @@
using System.ComponentModel.Design;
using System.Data.SqlClient;
using Models;
namespace Logic;
public interface ICommentRepository
{
public List<Comment> GetAllCommentsOnAnnouncement(int announcementId);
public List<Comment> GetAllCommentResponses(int commentId);
public Comment GetCommentById(int id);
public void UpdateComment(int id, string description);
public Comment CreateComment(User author, string description, string title, DateTime publishDate);
public void CreateCommentOnAnnouncement(User author, string description, string title, DateTime publishDate, int announcementId);
public void CreateResponseOnComment(User author, string description, string title, DateTime publishDate, int commentId);
public void DeleteComment(int id);
public void DeleteCommentOnAnnouncement(int commentId, int announcementId);
public void DeleteResponseOnComment(int responseId, int commentId);
}

View File

@@ -0,0 +1,20 @@
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Logic
{
public interface IUserRepository
{
public List<User> GetAllUsers();
public User GetUserById(int id);
public User GetUserByName(string userName);
public List<User> GetUsersByPage(int p, int c);
public User CreateUser(string name, string password, UserRole role);
public void UpdateUser(int id, string name, string password, UserRole role);
public void DisableUser(int id);
}
}

View File

@@ -11,7 +11,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Data\Data.csproj" />
<ProjectReference Include="..\Models\Models.csproj" /> <ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -1,6 +1,5 @@
using BCrypt.Net; using BCrypt.Net;
using Models; using Models;
using Data;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
@@ -15,10 +14,10 @@ namespace Logic
{ {
public class UserManager public class UserManager
{ {
private UserRepository userRepository; private readonly IUserRepository userRepository;
public UserManager() public UserManager(IUserRepository userRepository)
{ {
userRepository = new UserRepository(); this.userRepository = userRepository;
} }
public List<User> GetAllUsers() public List<User> GetAllUsers()
{ {
@@ -28,29 +27,38 @@ namespace Logic
{ {
return userRepository.GetUserById(id); return userRepository.GetUserById(id);
} }
public List<User> GetUsersByPage(int? p, int? c) public List<User> GetUsersByPage(int p = 0, int c = 10)
{ {
return userRepository.GetUsersByPage(p, c); return userRepository.GetUsersByPage(p, c);
} }
public User? AuthenticatedUser(string name, string password) public User? AuthenticatedUser(string name, string password)
{ {
List<User> users = userRepository.GetAllUsers(); List<User> users = userRepository.GetAllUsers();
User user = users.Find(x => x.Name == name); User? user = users.Find(x => x.Name == name);
if (user == null) if (name == null || password == null)
{ {
return null; throw new ArgumentNullException();
} }
else if (user != null && BCrypt.Net.BCrypt.Verify(password, user.Password))
{ {
if (BCrypt.Net.BCrypt.Verify(password, user.Password)) return user;
{
return user;
}
else return null;
} }
return null;
} }
public bool CreateUser(string name, string password, UserRole role) public bool UserExists(string name)
{ {
return userRepository.GetUserByName(name) != null;
}
public User CreateUser(string name, string password, UserRole role)
{
if (UserExists(name))
{
throw new ArgumentException("User with given username already exists!");
}
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(password))
{
throw new ArgumentException("Name or password should not be empty");
}
return userRepository.CreateUser(name, password, role); return userRepository.CreateUser(name, password, role);
} }
public void UpdateUser(int id, string name, string password, UserRole role) public void UpdateUser(int id, string name, string password, UserRole role)

View File

@@ -5,7 +5,7 @@ using System.Text;
namespace Models namespace Models
{ {
public class Announcement : GenericMessage, IVotable public class Announcement : GenericMessage
{ {
public Announcement(int id, User author, string description, string title, DateTime publishDate, bool isImportant, bool isSticky) : base(id, author, description, title, publishDate) public Announcement(int id, User author, string description, string title, DateTime publishDate, bool isImportant, bool isSticky) : base(id, author, description, title, publishDate)
{ {
@@ -31,16 +31,6 @@ namespace Models
{ {
get; set; get; set;
} }
public void DownVote()
{
throw new NotImplementedException();
}
public void UpVote()
{
throw new NotImplementedException();
}
public override string ToString() public override string ToString()
{ {
return $"{Title} ({PublishDate.ToString("g")} - {Author.Name})"; return $"{Title} ({PublishDate.ToString("g")} - {Author.Name})";

View File

@@ -5,7 +5,7 @@ using System.Text;
namespace Models namespace Models
{ {
public class Comment : GenericMessage, IVotable public class Comment : GenericMessage
{ {
public Comment(int id, User author, string description, string title, DateTime publishDate) : base(id, author, description, title, publishDate) public Comment(int id, User author, string description, string title, DateTime publishDate) : base(id, author, description, title, publishDate)
{ {
@@ -13,15 +13,6 @@ namespace Models
} }
public List<Comment> Responses { get; set; } public List<Comment> Responses { get; set; }
public void DownVote()
{
throw new NotImplementedException();
}
public void UpVote()
{
throw new NotImplementedException();
}
public override string ToString() public override string ToString()
{ {
return $"{Author.Name} ({PublishDate.ToString("g")}) - {Description.PadRight(100).Trim()}"; return $"{Author.Name} ({PublishDate.ToString("g")}) - {Description.PadRight(100).Trim()}";

View File

@@ -7,11 +7,6 @@ namespace Models
{ {
public abstract class GenericMessage public abstract class GenericMessage
{ {
private User author;
private string description;
private string title;
private DateTime publishDate;
protected GenericMessage(int id, User author, string description, string title, DateTime publishDate) protected GenericMessage(int id, User author, string description, string title, DateTime publishDate)
{ {
ID = id; ID = id;
@@ -31,23 +26,19 @@ namespace Models
public User Author public User Author
{ {
get => author; get;set;
set => author = value;
} }
public string Description public string Description
{ {
get => description; get;set;
set => description = value;
} }
public string Title public string Title
{ {
get => title; get;set;
set => title = value;
} }
public DateTime PublishDate public DateTime PublishDate
{ {
get => publishDate; get; set;
set => publishDate = value;
} }
} }
} }

View File

@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Models
{
public interface IVotable
{
void UpVote()
{
throw new NotImplementedException();
}
void DownVote()
{
throw new NotImplementedException();
}
}
}

View File

@@ -9,10 +9,6 @@ namespace Models
{ {
public class User public class User
{ {
private int id;
private string name;
private string password;
private UserRole role;
public User(int id, string name, string password, UserRole role) public User(int id, string name, string password, UserRole role)
{ {
@@ -23,29 +19,26 @@ namespace Models
} }
public User() public User()
{ {
} }
public int ID public int ID
{ {
get; private set; get; set;
} }
public string Name public string Name
{ {
get => name; get; set;
set => name = value;
} }
[DataType(DataType.Password)] [DataType(DataType.Password)]
public string Password public string Password
{ {
get => password; get; set;
set => password = value;
} }
public UserRole Role public UserRole Role
{ {
get => role; get; set;
set => role = value;
} }
public override string ToString() public override string ToString()
{ {

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests
{
[TestClass]
public class AnnouncementManagerTest
{
}
}

View File

@@ -0,0 +1,60 @@
using Logic;
using Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Tests.Mocks
{
public class AnnouncementRepositoryFake : IAnnouncementRepository
{
private List<Announcement> announcements;
private int currentId;
public AnnouncementRepositoryFake()
{
announcements = new List<Announcement>();
currentId = 1;
}
public void CreateAnnouncement(string title, string description, User author, DateTime publishDate, bool isImportant, bool isSticky)
{
announcements.Add(new Announcement(currentId, author, description, title, publishDate, isImportant, isSticky));
currentId++;
}
public void DeleteAnnouncement(int id)
{
announcements.RemoveAt(id--);
}
public List<Announcement> GetAllAnnouncements()
{
return announcements;
}
public Announcement GetAnnouncementById(int id)
{
return announcements.FirstOrDefault(x => x.ID == id);
}
public List<Announcement> GetAnnouncementsByPage(int p, int c)
{
return announcements.GetRange(p + c, c);
}
public void UpdateAnnouncement(int id, string title, string description, bool isImportant, bool isSticky)
{
Announcement announcement = announcements.First(x => x.ID == id);
announcement.Title = title;
announcement.Description = description;
announcement.IsImportant = isImportant;
announcement.IsSticky = isSticky;
}
}
}

View File

@@ -0,0 +1,64 @@
using Models;
using Logic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Mocks
{
public class UserRepositoryFake : IUserRepository
{
private List<User> users;
private int currentId;
public UserRepositoryFake()
{
users = new List<User>();
currentId = 1;
}
public User CreateUser(string name, string password, UserRole role)
{
User user = new User(currentId, name, password, role);
users.Add(user);
currentId++;
return user;
}
public void DisableUser(int id)
{
User user = users.First(x => x.ID == id);
user.Name = $"Deleted User {user.ID}";
user.Password = "0";
}
public List<User> GetAllUsers()
{
return users;
}
public User GetUserById(int id)
{
return users.First(x => x.ID == id);
}
public User GetUserByName(string userName)
{
return users.FirstOrDefault(x => x.Name == userName);
}
public List<User> GetUsersByPage(int p, int c)
{
return users.GetRange(p + c, c);
}
public void UpdateUser(int id, string name, string password, UserRole role)
{
User user = users.First(x => x.ID == id);
user.Name = name;
user.Password = password;
user.Role = role;
}
}
}

View File

@@ -16,4 +16,9 @@
<PackageReference Include="coverlet.collector" Version="3.2.0" /> <PackageReference Include="coverlet.collector" Version="3.2.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Logic\Logic.csproj" />
<ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,11 +0,0 @@
namespace Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
}
}
}

View File

@@ -0,0 +1,153 @@
using BCrypt.Net;
using Logic;
using Models;
using Tests.Mocks;
namespace Tests
{
[TestClass]
public class UserManagerTest
{
// constants
readonly string USER_NAME = "user";
readonly string USER_PASSWORD = "password";
[TestMethod]
public void AuthenticatedUserWrongPasswordTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
// Act
userManager.CreateUser(USER_NAME, BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD), UserRole.TENANT);
User? result = userManager.AuthenticatedUser(USER_NAME, "incorrect");
// Assert
Assert.IsNull(result);
}
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void AuthenticatedUserNullPasswordTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
// Act
userManager.CreateUser(USER_NAME, BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD), UserRole.TENANT);
userManager.AuthenticatedUser(USER_NAME, null);
// Assert
// ArgumentNullException expected
}
[TestMethod]
public void AuthenticatedUserWrongNameTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
userManager.CreateUser(USER_NAME, USER_PASSWORD, UserRole.TENANT);
// Act
User? result = userManager.AuthenticatedUser("incorrect", USER_PASSWORD);
// Assert
Assert.IsNull(result);
}
[TestMethod]
public void AuthenticatedUserCorrectDetailsTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
User user = userManager.CreateUser(USER_NAME, BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD), UserRole.TENANT);
// Act
User? result = userManager.AuthenticatedUser(USER_NAME, USER_PASSWORD);
// Assert
Assert.AreEqual(user, result);
}
[TestMethod]
public void CreateUserCorrectDetailsTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
int userId = 1;
string hashedPassword = BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD);
User user = new User(userId, USER_NAME, hashedPassword, UserRole.TENANT);
// Act
User result = userManager.CreateUser(USER_NAME, hashedPassword, UserRole.TENANT);
// Assert
Assert.AreEqual(user.ID, result.ID);
Assert.AreEqual(user.Name, result.Name);
Assert.AreEqual(user.Password, result.Password);
Assert.AreEqual(user.Role, result.Role);
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void CreateUserDuplicateNameTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
// Act
userManager.CreateUser(USER_NAME, BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD), UserRole.TENANT);
userManager.CreateUser(USER_NAME, BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD), UserRole.TENANT);
// Assert
// ArgumentException expected
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void CreateUserEmptyNameTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
// Act
userManager.CreateUser("", BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD), UserRole.TENANT);
// Assert
// ArgumentException expected
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void CreateUserEmptyPasswordTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
// Act
userManager.CreateUser(USER_NAME, "", UserRole.TENANT);
// Assert
// ArgumentException expected
}
[TestMethod]
public void DisableUserTest()
{
// Arrange
UserManager userManager = new UserManager(new UserRepositoryFake());
User user = userManager.CreateUser(USER_NAME, BCrypt.Net.BCrypt.HashPassword(USER_PASSWORD), UserRole.TENANT);
// Act
userManager.DisableUser(user.ID);
// Assert
Assert.AreEqual(user.Name, $"Deleted User {user.ID}");
Assert.AreEqual(user.Password, "0");
}
}
}

View File

@@ -3,16 +3,23 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Logic; using Logic;
using Models; using Models;
using Data;
namespace WebApp.Pages namespace WebApp.Pages
{ {
[Authorize] [Authorize]
public class AnnouncementModel : PageModel public class AnnouncementModel : PageModel
{ {
private readonly IAnnouncementRepository _announcementRepository;
public AnnouncementModel(IAnnouncementRepository announcementRepository)
{
_announcementRepository = announcementRepository;
}
public void OnGet(int id) public void OnGet(int id)
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(_announcementRepository);
ViewData.Add("announcement", announcementManager.GetAllAnnouncements().Where(x => x.ID == id).First()); ViewData.Add("announcement", announcementManager.GetAllAnnouncements().First(x => x.ID == id));
} }
} }
} }

View File

@@ -4,12 +4,26 @@
@model WebApp.Pages.AnnouncementsModel @model WebApp.Pages.AnnouncementsModel
@{ @{
ViewData["Title"] = "Announcements"; ViewData["Title"] = "Announcements";
List<Announcement> announcements = ((List<Announcement>)ViewData["announcements"]).OrderByDescending(x => x.PublishDate).OrderByDescending(x => x.IsSticky).ToList(); List<Announcement> announcements = ((List<Announcement>)ViewData["announcements"]).OrderByDescending(x => x.IsSticky).ToList();
int currentPage = @Convert.ToInt32(ViewData["page"]); int currentPage = 0;
if (ViewData["page"] != null)
{
currentPage = Convert.ToInt32(ViewData["page"]);
}
} }
<a href="./CreateAnnouncement" class="btn btn-primary">Create new announcement</a> <a href="./CreateAnnouncement" class="btn btn-primary">Create new announcement</a>
<form method="get">
<div class="form-actions no-color">
<p>
<input type="hidden" name="handler" value="search" />
<input type="text" name="s" />
<input type="submit" asp-page-handler="Search" value="Search" class="btn btn-default" />
</p>
</div>
</form>
<div class="mb-3 mt-3"> <div class="mb-3 mt-3">
@foreach (Announcement announcement in announcements) @foreach (Announcement announcement in announcements)
{ {
@@ -27,7 +41,9 @@
} }
</div> </div>
<nav aria-label="Page navigation"> @if (ViewData["page"] != null)
{
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center"> <ul class="pagination justify-content-center">
@if (currentPage <= 1) @if (currentPage <= 1)
{ {
@@ -57,4 +73,5 @@
@: </li> @: </li>
} }
</ul> </ul>
</nav> </nav>
}

View File

@@ -11,21 +11,33 @@ namespace WebApp.Pages
public class AnnouncementsModel : PageModel public class AnnouncementsModel : PageModel
{ {
public AnnouncementManager AnnouncementManager { get; set; } public AnnouncementManager AnnouncementManager { get; set; }
public void OnGet(int? p, int? c) private readonly IAnnouncementRepository _announcementRepository;
public AnnouncementsModel(IAnnouncementRepository announcementRepository)
{ {
AnnouncementManager = new AnnouncementManager(); _announcementRepository = announcementRepository;
if (p == null || p < 1) }
public void OnGet(int? p, int? c) // page, count
{
AnnouncementManager = new AnnouncementManager(_announcementRepository);
if (!(p < 0))
{ {
p = 1; p = 1;
} }
if (c == null || c < 1) if (!(c < 1))
{ {
c = 10; c = 10;
} }
ViewData.Add("announcements", AnnouncementManager.GetAnnouncementsByPage(p - 1, c)); ViewData.Add("announcements", AnnouncementManager.GetAnnouncementsByPage(p.Value - 1, c.Value));
ViewData.Add("page", p); ViewData.Add("page", p);
ViewData.Add("count", c); ViewData.Add("count", c);
ViewData.Add("allCount", AnnouncementManager.GetAllAnnouncements().Count()); ViewData.Add("allCount", AnnouncementManager.GetAllAnnouncements().Count);
}
public void OnGetSearch(string s) // search
{
AnnouncementManager = new AnnouncementManager(_announcementRepository);
ViewData.Add("announcements", AnnouncementManager.SearchAnnouncements(s));
} }
} }
} }

View File

@@ -1,3 +1,4 @@
using Data;
using Logic; using Logic;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -29,7 +30,7 @@ namespace WebApp.Pages
} }
public void OnPost() public void OnPost()
{ {
UserManager userManager = new UserManager(); UserManager userManager = new UserManager(new UserRepository());
User user = userManager.GetUserById(int.Parse(User.FindFirstValue("id"))); User user = userManager.GetUserById(int.Parse(User.FindFirstValue("id")));
if (NewPassword == null) if (NewPassword == null)
{ {

View File

@@ -1,3 +1,4 @@
using Data;
using Logic; using Logic;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -17,8 +18,8 @@ namespace WebApp.Pages
} }
public IActionResult OnPost() public IActionResult OnPost()
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(new AnnouncementRepository());
UserManager userManager = new UserManager(); UserManager userManager = new UserManager(new UserRepository());
User user = userManager.GetUserById(int.Parse(User.FindFirstValue("id"))); User user = userManager.GetUserById(int.Parse(User.FindFirstValue("id")));
announcementManager.CreateAnnouncement(Announcement.Title, Announcement.Description, user, DateTime.Now, Announcement.IsImportant, Announcement.IsSticky); announcementManager.CreateAnnouncement(Announcement.Title, Announcement.Description, user, DateTime.Now, Announcement.IsImportant, Announcement.IsSticky);
return RedirectToPage("Announcements"); return RedirectToPage("Announcements");

View File

@@ -10,11 +10,17 @@ namespace WebApp.Pages
[Authorize] [Authorize]
public class DeleteAnnouncementModel : PageModel public class DeleteAnnouncementModel : PageModel
{ {
private readonly IAnnouncementRepository _announcementRepository;
public DeleteAnnouncementModel(IAnnouncementRepository announcementRepository)
{
_announcementRepository = announcementRepository;
}
[BindProperty] [BindProperty]
public int AnnouncementId { get; set; } public int AnnouncementId { get; set; }
public void OnGet(int id) public void OnGet(int id)
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(_announcementRepository);
if (id != null) if (id != null)
{ {
Announcement announcement = announcementManager.GetAnnouncementById(id); Announcement announcement = announcementManager.GetAnnouncementById(id);
@@ -26,7 +32,7 @@ namespace WebApp.Pages
} }
public IActionResult OnPost() public IActionResult OnPost()
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(_announcementRepository);
announcementManager.DeleteAnnouncement(AnnouncementId); announcementManager.DeleteAnnouncement(AnnouncementId);
return RedirectToPage("Announcements"); return RedirectToPage("Announcements");
} }

View File

@@ -10,11 +10,17 @@ namespace WebApp.Pages
[Authorize] [Authorize]
public class EditAnnouncementModel : PageModel public class EditAnnouncementModel : PageModel
{ {
private readonly IAnnouncementRepository _announcementRepository;
public EditAnnouncementModel(IAnnouncementRepository announcementRepository)
{
_announcementRepository = announcementRepository;
}
[BindProperty] [BindProperty]
public Announcement Announcement { get; set; } public Announcement Announcement { get; set; }
public void OnGet(int id) public void OnGet(int id)
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(_announcementRepository);
if (id != null) if (id != null)
{ {
Announcement announcement = announcementManager.GetAnnouncementById(id); Announcement announcement = announcementManager.GetAnnouncementById(id);
@@ -26,7 +32,7 @@ namespace WebApp.Pages
} }
public IActionResult OnPost() public IActionResult OnPost()
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(_announcementRepository);
announcementManager.UpdateAnnouncement(Announcement.ID, Announcement.Title, Announcement.Description, Announcement.IsImportant, Announcement.IsSticky); announcementManager.UpdateAnnouncement(Announcement.ID, Announcement.Title, Announcement.Description, Announcement.IsImportant, Announcement.IsSticky);
return RedirectToPage("Announcements"); return RedirectToPage("Announcements");
} }

View File

@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authentication.Cookies;
using Models; using Models;
using Logic; using Logic;
using System.Security.Claims; using System.Security.Claims;
using Data;
namespace WebApp.Pages namespace WebApp.Pages
{ {
@@ -19,7 +20,7 @@ namespace WebApp.Pages
public IActionResult OnPost(string? returnUrl) public IActionResult OnPost(string? returnUrl)
{ {
var userManager = new UserManager(); var userManager = new UserManager(new UserRepository());
User? user = userManager.AuthenticatedUser(MyUser.Name, MyUser.Password); User? user = userManager.AuthenticatedUser(MyUser.Name, MyUser.Password);
if (user != null) if (user != null)
{ {

View File

@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.RazorPages;
using Logic; using Logic;
using Models; using Models;
using Data;
namespace WebApp.Pages namespace WebApp.Pages
{ {
@@ -14,8 +15,8 @@ namespace WebApp.Pages
} }
public void OnPost() public void OnPost()
{ {
var userManager = new UserManager(); var userManager = new UserManager(new UserRepository());
if (userManager.CreateUser(MyUser.Name, BCrypt.Net.BCrypt.HashPassword(MyUser.Password), MyUser.Role)) if (userManager.CreateUser(MyUser.Name, BCrypt.Net.BCrypt.HashPassword(MyUser.Password), MyUser.Role) != null)
{ {
ViewData["confirm"] = $"Successfully registered {MyUser.Name}!"; ViewData["confirm"] = $"Successfully registered {MyUser.Name}!";
} }

View File

@@ -1,3 +1,5 @@
using Data;
using Logic;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
namespace WebApp namespace WebApp
@@ -16,6 +18,10 @@ namespace WebApp
options.AccessDeniedPath = new PathString("/Error/401"); options.AccessDeniedPath = new PathString("/Error/401");
}); });
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<ICommentRepository, CommentRepository>();
builder.Services.AddScoped<IAnnouncementRepository, AnnouncementRepository>();
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.

View File

@@ -22,6 +22,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Data\Data.csproj" />
<ProjectReference Include="..\Logic\Logic.csproj" /> <ProjectReference Include="..\Logic\Logic.csproj" />
<ProjectReference Include="..\Models\Models.csproj" /> <ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -1,4 +1,5 @@
using Logic; using Data;
using Logic;
using Models; using Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -56,7 +57,7 @@ namespace WinForms
private void btnSave_Click(object sender, EventArgs e) private void btnSave_Click(object sender, EventArgs e)
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(new AnnouncementRepository());
if (string.IsNullOrEmpty(tbTitle.Text)) if (string.IsNullOrEmpty(tbTitle.Text))
{ {
MessageBox.Show("Please enter a title"); MessageBox.Show("Please enter a title");
@@ -114,7 +115,7 @@ namespace WinForms
if (MessageBox.Show($"Are you sure you want to delete\n{currentComment.Title}\nCreated at {currentComment.PublishDate.ToString("g")} by {currentComment.Author.Name}", if (MessageBox.Show($"Are you sure you want to delete\n{currentComment.Title}\nCreated at {currentComment.PublishDate.ToString("g")} by {currentComment.Author.Name}",
"Delete announcement", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) "Delete announcement", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{ {
CommentManager commentManager = new CommentManager(); CommentManager commentManager = new CommentManager(new CommentRepository());
commentManager.DeleteCommentOnAnnouncement(currentComment.ID, announcement.ID); commentManager.DeleteCommentOnAnnouncement(currentComment.ID, announcement.ID);
} }
RefreshComments(); RefreshComments();

View File

@@ -1,4 +1,5 @@
using Logic; using Data;
using Logic;
using Models; using Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -43,13 +44,10 @@ namespace WinForms
btnViewComment.Enabled = false; btnViewComment.Enabled = false;
} }
if (comment != null && currentUser != null) if (comment != null && currentUser != null && currentUser.ID != comment.Author.ID)
{ {
if (currentUser.ID != comment.Author.ID) // restriction: only edit personal comments
{ readOnly = true;
// restriction: only edit personal comments
readOnly = true;
}
} }
if (readOnly) if (readOnly)
@@ -71,7 +69,7 @@ namespace WinForms
} }
private void btnSave_Click(object sender, EventArgs e) private void btnSave_Click(object sender, EventArgs e)
{ {
CommentManager commentManager = new CommentManager(); CommentManager commentManager = new CommentManager(new CommentRepository());
if (string.IsNullOrEmpty(tbTitle.Text) || string.IsNullOrEmpty(tbDescription.Text)) if (string.IsNullOrEmpty(tbTitle.Text) || string.IsNullOrEmpty(tbDescription.Text))
{ {
MessageBox.Show("Please enter a title and comment text"); MessageBox.Show("Please enter a title and comment text");
@@ -135,7 +133,7 @@ namespace WinForms
if (MessageBox.Show($"Are you sure you want to delete\n{currentResponse.Title}\nCreated at {currentResponse.PublishDate.ToString("g")} by {currentResponse.Author.Name}", if (MessageBox.Show($"Are you sure you want to delete\n{currentResponse.Title}\nCreated at {currentResponse.PublishDate.ToString("g")} by {currentResponse.Author.Name}",
"Delete announcement", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) "Delete announcement", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{ {
CommentManager commentManager = new CommentManager(); CommentManager commentManager = new CommentManager(new CommentRepository());
commentManager.DeleteResponseOnComment(currentResponse.ID, comment.ID); commentManager.DeleteResponseOnComment(currentResponse.ID, comment.ID);
} }
RefreshComments(); RefreshComments();

View File

@@ -1,4 +1,5 @@
using Logic; using Data;
using Logic;
using Models; using Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -70,7 +71,7 @@ namespace WinForms
User currentUser = (User)lbUsers.SelectedItem; User currentUser = (User)lbUsers.SelectedItem;
if (MessageBox.Show($"Are you sure you want to delete\n{currentUser.Name}\n{currentUser.Role}", "Delete user", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) if (MessageBox.Show($"Are you sure you want to delete\n{currentUser.Name}\n{currentUser.Role}", "Delete user", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{ {
UserManager userManager = new UserManager(); UserManager userManager = new UserManager(new UserRepository());
userManager.DisableUser(currentUser.ID); userManager.DisableUser(currentUser.ID);
} }
} }
@@ -107,13 +108,13 @@ namespace WinForms
private void RefreshLists() private void RefreshLists()
{ {
UserManager userManager = new UserManager(); UserManager userManager = new UserManager(new UserRepository());
lbUsers.Items.Clear(); lbUsers.Items.Clear();
foreach (User _user in userManager.GetAllUsers()) foreach (User _user in userManager.GetAllUsers())
{ {
lbUsers.Items.Add(_user); lbUsers.Items.Add(_user);
} }
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(new AnnouncementRepository());
lbAnnouncements.Items.Clear(); lbAnnouncements.Items.Clear();
foreach (Announcement announcement in announcementManager.GetAllAnnouncements()) foreach (Announcement announcement in announcementManager.GetAllAnnouncements())
{ {
@@ -145,7 +146,7 @@ namespace WinForms
if (MessageBox.Show($"Are you sure you want to delete\n{currentAnnouncement.Title}\nCreated at {currentAnnouncement.PublishDate.ToString("g")} by {currentAnnouncement.Author.Name}", if (MessageBox.Show($"Are you sure you want to delete\n{currentAnnouncement.Title}\nCreated at {currentAnnouncement.PublishDate.ToString("g")} by {currentAnnouncement.Author.Name}",
"Delete announcement", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) "Delete announcement", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{ {
AnnouncementManager announcementManager = new AnnouncementManager(); AnnouncementManager announcementManager = new AnnouncementManager(new AnnouncementRepository());
announcementManager.DeleteAnnouncement(currentAnnouncement.ID); announcementManager.DeleteAnnouncement(currentAnnouncement.ID);
} }
RefreshLists(); RefreshLists();

View File

@@ -1,3 +1,4 @@
using Data;
using Logic; using Logic;
using Models; using Models;
@@ -12,7 +13,7 @@ namespace WinForms
private void btnLogin_Click(object sender, EventArgs e) private void btnLogin_Click(object sender, EventArgs e)
{ {
UserManager userManager = new UserManager(); UserManager userManager = new UserManager(new UserRepository());
User? user = userManager.AuthenticatedUser(tbUsername.Text, tbPassword.Text); User? user = userManager.AuthenticatedUser(tbUsername.Text, tbPassword.Text);
if (user == null) if (user == null)
{ {

View File

@@ -1,4 +1,5 @@
using Logic; using Data;
using Logic;
using Models; using Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -41,7 +42,7 @@ namespace WinForms
private void btnSave_Click(object sender, EventArgs e) private void btnSave_Click(object sender, EventArgs e)
{ {
UserManager userManager = new UserManager(); UserManager userManager = new UserManager(new UserRepository());
if (string.IsNullOrEmpty(tbUsername.Text) || string.IsNullOrEmpty(tbPassword.Text) || cbUserRole.SelectedIndex == -1) if (string.IsNullOrEmpty(tbUsername.Text) || string.IsNullOrEmpty(tbPassword.Text) || cbUserRole.SelectedIndex == -1)
{ {
MessageBox.Show("Please enter data in all fields"); MessageBox.Show("Please enter data in all fields");

View File

@@ -10,6 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Data\Data.csproj" />
<ProjectReference Include="..\Logic\Logic.csproj" /> <ProjectReference Include="..\Logic\Logic.csproj" />
<ProjectReference Include="..\Models\Models.csproj" /> <ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup> </ItemGroup>

Binary file not shown.