Skip to content

Commit 953f6cc

Browse files
Merge pull request #333 from ITU-BDSA2024-GROUP10/see-the-following-and-follower-count-on-about-me
See the following and follower count on about me
2 parents 2adf5ab + 59ca4f7 commit 953f6cc

File tree

9 files changed

+148
-16
lines changed

9 files changed

+148
-16
lines changed

Chirp/src/Chirp.Core/AuthorService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace Chirp.Core;
66
public interface IAuthorService
77
{
88
public List<AuthorDTO> GetFollows(string username);
9+
public List<AuthorDTO> GetFollowers(string username);
910
public bool Follow(string currentUser, string userToFollow);
1011
public bool Unfollow(string currentUser, string userToUnFollow);
1112
public bool MakeFollowersUnfollow(string username);
@@ -16,6 +17,11 @@ public List<AuthorDTO> GetFollows(string username)
1617
{
1718
return db.GetAuthorFollows(username).Result;
1819
}
20+
21+
public List<AuthorDTO> GetFollowers(string username)
22+
{
23+
return db.GetAuthorFollowers(username).Result;
24+
}
1925

2026
public bool MakeFollowersUnfollow(string username)
2127
{

Chirp/src/Chirp.Core/IAuthorRepository.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public interface IAuthorRepository
77
public Task<AuthorDTO?> GetAuthorByName(string name);
88
public Task<bool> AddAuthor(AuthorDTO author);
99
public Task<List<AuthorDTO>> GetAuthorFollows(string username);
10+
public Task<List<AuthorDTO>> GetAuthorFollowers(string username);
1011
public Task<bool> Follow (string currentUser, string userToFollow);
1112
public Task<bool> UnFollow (string currentUser, string userToUnFollow);
1213
public Task<bool> MakeFollowersUnfollow(string user);

Chirp/src/Chirp.Infrastructure/AuthorRepository.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ public async Task<List<AuthorDTO>> GetAuthorFollows(string username)
3636
return GetFollowing(username).Result.Select(a => new AuthorDTO(a.UserName!, a.Email!)).ToList();
3737
}
3838

39+
public async Task<List<AuthorDTO>> GetAuthorFollowers(string username)
40+
{
41+
if (!await UserExists(username)) throw new UserDoesNotExist();
42+
var followers = await context.Authors
43+
.Where(a => a.NormalizedUserName == username.ToUpper())
44+
.Select(a => a.Followers)
45+
.FirstOrDefaultAsync() ?? new List<Author>();
46+
47+
return followers.Select(a => new AuthorDTO(a.UserName!, a.Email!)).ToList();
48+
}
49+
3950
public async Task<bool> Follow(string currentUser, string userToFollow)
4051
{
4152
if (currentUser == userToFollow) throw new ArgumentException("You cannot follow yourself");

Chirp/src/Chirp.Web/Pages/AboutMe.cshtml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
<div>
1818
<h2>Name: @Model.Author!.UserName</h2>
1919
<h3>Email: @Model.Author.Email</h3>
20+
<div style="display: flex;">
21+
<h4>Following: @Model.AmountYouFollow</h4>
22+
<div style="margin-right: 25px"></div>
23+
<h4>Followers: @Model.AmountOfFollowers</h4>
24+
</div>
25+
2026
@if (Model.Cheeps.Count == 1)
2127
{
2228
<h4>You have Cheep'd: @Model.Cheeps.Count time</h4>
@@ -40,4 +46,3 @@
4046

4147
@await Component.InvokeAsync("CheepList", new {cheeps = Model.Cheeps, targetPage = "/AboutMe"})
4248
</div>
43-

Chirp/src/Chirp.Web/Pages/AboutMe.cshtml.cs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,59 @@
88
using Microsoft.AspNetCore.Identity;
99
using Microsoft.EntityFrameworkCore.Metadata.Internal;
1010
using Microsoft.AspNetCore.Authentication;
11+
using NUnit.Framework;
1112

1213
namespace Chirp.Web.Pages;
1314

1415
public class AboutMe(IAuthorService authorService, ICheepService cheepService, SignInManager<Author> signInManager, UserManager<Author> userManager) : PageModel
1516
{
1617
public Author? Author { get; set; }
1718
public List<CheepDTO> Cheeps { get; set; } = [];
19+
public int AmountYouFollow { get; set; } = 0;
20+
public int AmountOfFollowers { get; set; } = 0;
1821
public async void OnGet()
1922
{
2023
Author = await userManager.FindByNameAsync(User.Identity!.Name!);
21-
Cheeps = (cheepService.GetCheepsFromAuthor(Author!.UserName!)).ToList();
24+
if (Author?.UserName == null)
25+
{
26+
Redirect("/NotFound");
27+
return;
28+
}
29+
30+
SetUserInfo(Author.UserName);
2231
}
2332

2433
public async Task<ActionResult> OnPostConfirmDelete()
2534
{
26-
await SignOutAndDeleteUser();
35+
try
36+
{
37+
await SignOutAndDeleteUser();
38+
}
39+
catch
40+
{
41+
return Redirect("/NotFound");
42+
}
43+
2744
return Redirect("/");
2845
}
2946

3047
public async Task SignOutAndDeleteUser()
3148
{
3249
var authorName = User.Identity!.Name!;
33-
await signInManager.SignOutAsync();
50+
3451
Author = await userManager.FindByNameAsync(authorName);
35-
if (Author != null)
52+
if (Author?.UserName != null)
3653
{
37-
authorService.MakeFollowersUnfollow(Author.UserName!);
54+
await signInManager.SignOutAsync();
55+
authorService.MakeFollowersUnfollow(Author.UserName);
3856
await userManager.DeleteAsync(Author);
39-
} else throw new Exception("Author could not be found");
57+
} else throw new Exception("Author data is not valid");
58+
}
59+
60+
private void SetUserInfo(string authorUsername)
61+
{
62+
Cheeps = cheepService.GetCheepsFromAuthor(authorUsername);
63+
AmountYouFollow = authorService.GetFollows(authorUsername).Count;
64+
AmountOfFollowers = authorService.GetFollowers(authorUsername).Count;
4065
}
4166
}

Chirp/test/PlaywrightTests/EndToEndTests.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,51 @@ public async Task ChirpTextRedirectsToMainPage()
6868
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Public Timeline" })).ToBeVisibleAsync();
6969
Assert.That(Page.Url, Is.EqualTo($"{RazorBaseUrl}/?page=1"));
7070
}
71+
72+
[Test]
73+
public async Task ForgetMe()
74+
{
75+
#region Arrange
76+
77+
var testAuthor1 = new TestAuthorBuilder(RazorFactory.GetUserManager())
78+
.WithUsernameAndEmail("mr. test1")
79+
.GetTestAuthor();
80+
81+
var testAuthor2 = new TestAuthorBuilder(RazorFactory.GetUserManager())
82+
.WithUsernameAndEmail("mr. test2")
83+
.GetTestAuthor();
84+
85+
var testAuthor3 = new TestAuthorBuilder(RazorFactory.GetUserManager())
86+
.WithUsernameAndEmail("mr. test3")
87+
.GetTestAuthor();
88+
89+
testAuthor1.AddFollow(testAuthor2);
90+
testAuthor3.AddFollow(testAuthor1);
91+
92+
//because of the following relation, the other testauthors gets created when we create testAuthor1
93+
testAuthor1.Create();
94+
95+
#endregion
96+
97+
await RazorPageUtils.Login(testAuthor1);
98+
await Page.GetByRole(AriaRole.Link, new() { Name = "About Me" }).ClickAsync();
99+
await Page.GetByRole(AriaRole.Button, new() { Name = "Forget Me" }).ClickAsync();
100+
await Page.GetByRole(AriaRole.Button, new() { Name = "Yes, Delete" }).ClickAsync();
101+
102+
var author1 = await RazorFactory.GetDbContext().Authors.FindAsync(testAuthor1.UserName);
103+
var author2Followers = RazorFactory.GetDbContext().Authors
104+
.Where(a => a.NormalizedUserName == testAuthor2.UserName!.ToUpper())
105+
.SelectMany(a => a.Followers);
106+
107+
var author3Following = RazorFactory.GetDbContext().Authors
108+
.Where(a => a.NormalizedUserName == testAuthor3.UserName!.ToUpper())
109+
.SelectMany(a => a.Following);
110+
111+
await Expect(Page.Locator("body")).ToContainTextAsync("login");
112+
Assert.That(Page.Url, Is.EqualTo($"{RazorBaseUrl}/?page=1"));
113+
Assert.That(author1, Is.Null);
114+
Assert.That(author2Followers, Is.Empty);
115+
Assert.That(author3Following, Is.Empty);
116+
117+
}
71118
}

Chirp/test/PlaywrightTests/UITests/AboutMeTests.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,33 @@ public async Task CannotSeeAboutMeLinkWhenNotRegistered()
2929
[Test]
3030
public async Task AboutMePageShowsUserInfo()
3131
{
32-
var testAuthor = new TestAuthorBuilder(RazorFactory.GetUserManager())
33-
.WithDefault()
34-
.Create();
32+
var testAuthor1 = new TestAuthorBuilder(RazorFactory.GetUserManager())
33+
.WithUsernameAndEmail("mr. test1")
34+
.GetTestAuthor();
35+
var testAuthor2 = new TestAuthorBuilder(RazorFactory.GetUserManager())
36+
.WithUsernameAndEmail("mr. test2")
37+
.GetTestAuthor();
3538

36-
await RazorPageUtils.Login(testAuthor);
39+
var testAuthorMain = new TestAuthorBuilder(RazorFactory.GetUserManager())
40+
.WithUsernameAndEmail("mr. testMain")
41+
.GetTestAuthor();
42+
43+
testAuthorMain.AddFollow(testAuthor1);
44+
testAuthorMain.AddFollow(testAuthor2);
45+
testAuthor1.AddFollow(testAuthorMain);
46+
47+
testAuthorMain.Create();
48+
49+
await GenerateCheeps(testAuthorMain.author, 365);
50+
51+
await RazorPageUtils.Login(testAuthorMain);
3752

3853
await Page.GetByRole(AriaRole.Link, new() { Name = "About Me" }).ClickAsync();
39-
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = $"Name: {testAuthor.UserName}" })).ToBeVisibleAsync();
40-
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = $"Email: {testAuthor.Email}" })).ToBeVisibleAsync();
41-
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "You have Cheep'd: 0 times" })).ToBeVisibleAsync();
54+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = $"Name: {testAuthorMain.UserName}" })).ToBeVisibleAsync();
55+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = $"Email: {testAuthorMain.Email}" })).ToBeVisibleAsync();
56+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "You have Cheep'd: 365 times" })).ToBeVisibleAsync();
57+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Following: 2" })).ToBeVisibleAsync();
58+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Followers: 1" })).ToBeVisibleAsync();
4259
}
4360

4461
[Test]

Chirp/test/PlaywrightTests/Utils/TestAuthorBuilder.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ namespace PlaywrightTests.Utils;
66

77
public class TestAuthor
88
{
9-
public TestAuthor()
9+
private TestAuthorBuilder _testAuthorBuilder { get; set; }
10+
public TestAuthor(TestAuthorBuilder testAuthorBuilder)
1011
{
12+
_testAuthorBuilder = testAuthorBuilder;
1113
}
1214

1315
public Author author { get; set; } = new Author();
@@ -16,6 +18,18 @@ public TestAuthor()
1618
public string? UserName => author.UserName;
1719
public string? Email => author.Email;
1820
public List<Author> Follows => author.Following;
21+
public List<Author> Followers => author.Followers;
22+
23+
public void AddFollow(TestAuthor testAuthor)
24+
{
25+
testAuthor.Followers.Add(author);
26+
author.Following.Add(testAuthor.author);
27+
}
28+
29+
public void Create()
30+
{
31+
_testAuthorBuilder.Create();
32+
}
1933
}
2034

2135
public class TestAuthorBuilder
@@ -25,7 +39,7 @@ public class TestAuthorBuilder
2539

2640
public TestAuthorBuilder(UserManager<Author> userManager)
2741
{
28-
_testAuthor = new TestAuthor();
42+
_testAuthor = new TestAuthor(this);
2943
_userManager = userManager;
3044
_testAuthor.Password = "Password123!";
3145
}
@@ -41,6 +55,11 @@ public TestAuthor Create()
4155
_userManager.CreateAsync(_testAuthor.author, _testAuthor.Password).Wait();
4256
return _testAuthor;
4357
}
58+
59+
public TestAuthor GetTestAuthor()
60+
{
61+
return _testAuthor;
62+
}
4463

4564
public TestAuthorBuilder WithUsername(string username)
4665
{

Chirp/test/Utils/TestUtilities/InMemoryCostumeWebApplicationFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
5252
{
5353
var connection = container.GetRequiredService<DbConnection>();
5454
options.UseSqlite(connection);
55+
options.EnableSensitiveDataLogging();
5556
});
5657
});
5758

0 commit comments

Comments
 (0)