Profile page, tweaked banlist/follows
This commit is contained in:
parent
6a9b14e7e9
commit
482079fb8f
@ -40,6 +40,7 @@ class FollowsController(
|
|||||||
|
|
||||||
@GetMapping("follows")
|
@GetMapping("follows")
|
||||||
fun getFollowsBanStatus(): ResponseEntity<FollowsBanStatusResponse> {
|
fun getFollowsBanStatus(): ResponseEntity<FollowsBanStatusResponse> {
|
||||||
|
authService.getCurrentUser().userId
|
||||||
val follows = dslContext.select(
|
val follows = dslContext.select(
|
||||||
USERS.USER_ID,
|
USERS.USER_ID,
|
||||||
USERS.USERNAME,
|
USERS.USERNAME,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import org.springframework.security.authentication.AnonymousAuthenticationToken
|
|||||||
import org.springframework.security.core.context.SecurityContextHolder
|
import org.springframework.security.core.context.SecurityContextHolder
|
||||||
import org.springframework.security.oauth2.core.user.DefaultOAuth2User
|
import org.springframework.security.oauth2.core.user.DefaultOAuth2User
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class AuthService(
|
class AuthService(
|
||||||
@ -14,7 +15,11 @@ class AuthService(
|
|||||||
|
|
||||||
data class UserInfo(
|
data class UserInfo(
|
||||||
val userId: Long,
|
val userId: Long,
|
||||||
val username: String
|
val username: String,
|
||||||
|
|
||||||
|
val country: String?,
|
||||||
|
val joinDate: OffsetDateTime?,
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun isAdmin(): Boolean {
|
fun isAdmin(): Boolean {
|
||||||
@ -39,7 +44,9 @@ class AuthService(
|
|||||||
|
|
||||||
return UserInfo(
|
return UserInfo(
|
||||||
userId = (userDetails.attributes["id"] as Int).toLong(),
|
userId = (userDetails.attributes["id"] as Int).toLong(),
|
||||||
username = userDetails.attributes["username"] as String
|
username = userDetails.attributes["username"] as String,
|
||||||
|
country = userDetails.attributes["countryCode"] as String?,
|
||||||
|
joinDate = OffsetDateTime.parse(userDetails.attributes["joinDate"] as String)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ RUN sed -i '238s|return \[x for x in arr if lower_limit < x < upper_limit\]|arr_
|
|||||||
|
|
||||||
COPY ./src/ ./src/
|
COPY ./src/ ./src/
|
||||||
|
|
||||||
ENV GUNICORN_CMD_ARGS="--bind=0.0.0.0:5000 --workers=10"
|
ENV GUNICORN_CMD_ARGS="--bind=0.0.0.0:5000 --workers=16"
|
||||||
|
|
||||||
# Run gunicorn with the application
|
# Run gunicorn with the application
|
||||||
CMD ["gunicorn", "--chdir", "src", "main:app"]
|
CMD ["gunicorn", "--chdir", "src", "main:app"]
|
||||||
@ -9,7 +9,7 @@ import {ViewReplayPairComponent} from "./view-replay-pair/view-replay-pair.compo
|
|||||||
import {SearchComponent} from "./search/search.component";
|
import {SearchComponent} from "./search/search.component";
|
||||||
import {ContributeComponent} from "./contribute/contribute.component";
|
import {ContributeComponent} from "./contribute/contribute.component";
|
||||||
import {BanlistComponent} from "./banlist/banlist.component";
|
import {BanlistComponent} from "./banlist/banlist.component";
|
||||||
import {FollowsComponent} from "./follows/follows.component";
|
import {ProfileComponent} from "./profile/profile.component";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: 'sus/:f', component: ViewSuspiciousScoresComponent, title: '/sus/'},
|
{path: 'sus/:f', component: ViewSuspiciousScoresComponent, title: '/sus/'},
|
||||||
@ -25,7 +25,7 @@ const routes: Routes = [
|
|||||||
|
|
||||||
{path: 'p/:replay1Id/:replay2Id', component: ViewReplayPairComponent},
|
{path: 'p/:replay1Id/:replay2Id', component: ViewReplayPairComponent},
|
||||||
|
|
||||||
{path: 'follows', component: FollowsComponent, title: '/follows/'},
|
{path: 'profile', component: ProfileComponent},
|
||||||
{path: 'banlist', component: BanlistComponent, title: '/ban/'},
|
{path: 'banlist', component: BanlistComponent, title: '/ban/'},
|
||||||
{path: 'contribute', component: ContributeComponent, title: '/contribute/ <3'},
|
{path: 'contribute', component: ContributeComponent, title: '/contribute/ <3'},
|
||||||
|
|
||||||
|
|||||||
@ -15,3 +15,10 @@
|
|||||||
.link-pink:hover {
|
.link-pink:hover {
|
||||||
color: rgba(234, 78, 179, 0.97)
|
color: rgba(234, 78, 179, 0.97)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
padding: 1px 2px 2px 1px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px dashed rgba(151, 151, 151, 0.97);
|
||||||
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
</form>
|
</form>
|
||||||
<div style="margin-top: 3px">
|
<div style="margin-top: 3px">
|
||||||
<ng-container *ngIf="this.userService.isUserLoggedIn()">
|
<ng-container *ngIf="this.userService.isUserLoggedIn()">
|
||||||
hi, <span class="user-details" [title]="this.userService.currentUser?.username">{{this.userService.currentUser?.username}}</span> <a [href]="this.userService.getLogoutUrl()">Logout</a>
|
hi, <span class="user-details" [title]="this.userService.currentUser?.username"><a [routerLink]="['/profile']"> {{this.userService.currentUser?.username}}</a></span> <a class="logout-btn" [href]="this.userService.getLogoutUrl()">Logout</a>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="!this.userService.isUserLoggedIn()">
|
<ng-container *ngIf="!this.userService.isUserLoggedIn()">
|
||||||
<a [href]="this.userService.getLoginUrl()">Login</a>
|
<a [href]="this.userService.getLoginUrl()">Login</a>
|
||||||
@ -26,6 +26,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="main term text-center statistics">
|
||||||
|
Players: {{ this.statistics?.total_users | number }} | Beatmaps: {{ this.statistics?.total_beatmaps | number }} | Scores: {{ this.statistics?.total_scores | number }}
|
||||||
|
<ng-container *ngIf="this.statistics?.total_bans">
|
||||||
|
| <a [routerLink]="['/banlist']">Bans: {{ this.statistics?.total_bans | number }}</a>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
<div class="text-center version">
|
<div class="text-center version">
|
||||||
v20240309
|
v20240309
|
||||||
|
|||||||
@ -1,8 +1,21 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {Router, RouterLink, RouterOutlet} from "@angular/router";
|
import {Router, RouterLink, RouterOutlet} from "@angular/router";
|
||||||
import {UserService} from "../corelib/service/user.service";
|
import {UserService} from "../corelib/service/user.service";
|
||||||
import {NgIf} from '@angular/common';
|
import {DecimalPipe, NgIf} from '@angular/common';
|
||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
import {environment} from "../environments/environment";
|
||||||
|
import {LocalCacheService} from "../corelib/service/local-cache.service";
|
||||||
|
|
||||||
|
interface Statistics {
|
||||||
|
total_beatmaps: number;
|
||||||
|
total_users: number;
|
||||||
|
total_scores: number;
|
||||||
|
total_replay_scores: number;
|
||||||
|
total_replay_similarity: number;
|
||||||
|
total_bans: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@ -11,18 +24,34 @@ import {FormsModule} from '@angular/forms';
|
|||||||
RouterLink,
|
RouterLink,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
NgIf,
|
NgIf,
|
||||||
RouterOutlet
|
RouterOutlet,
|
||||||
|
DecimalPipe
|
||||||
],
|
],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.css']
|
styleUrls: ['./app.component.css']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
|
statistics: Statistics | null = null;
|
||||||
term: string = '';
|
term: string = '';
|
||||||
|
|
||||||
constructor(private router: Router,
|
constructor(private router: Router,
|
||||||
|
private localCacheService: LocalCacheService,
|
||||||
public userService: UserService
|
public userService: UserService
|
||||||
) {
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.getStatistics().subscribe((response: Statistics) => {
|
||||||
|
this.statistics = response;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatistics(): Observable<Statistics> {
|
||||||
|
return this.localCacheService.fetchData<Statistics>(
|
||||||
|
'statistics',
|
||||||
|
`${environment.apiUrl}/stats`,
|
||||||
|
60
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(): void {
|
onSubmit(): void {
|
||||||
|
|||||||
@ -21,7 +21,16 @@
|
|||||||
<ng-template #nullTemplate>
|
<ng-template #nullTemplate>
|
||||||
<code>null</code>
|
<code>null</code>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<table *ngIf="this.banlist">
|
<ng-container *ngIf="this.banlist">
|
||||||
|
<fieldset class="mb-2">
|
||||||
|
<legend>tools</legend>
|
||||||
|
<div class="text-center">
|
||||||
|
<button (click)="this.downloadFilesService.downloadCSV(this.banlist.users, ['userId', 'username', 'secondsPlayed', 'pp', 'rank', 'isBanned', 'approximateBanTime', 'lastUpdate'], 'nise-banlist')">Download .csv</button>
|
||||||
|
<button (click)="this.downloadFilesService.downloadJSON(this.banlist.users, 'nise-banlist')">Download .json</button>
|
||||||
|
<button (click)="this.downloadFilesService.downloadXLSX(this.banlist.users, 'nise-banlist')">Download .xlsx</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">Username</th>
|
<th colspan="2">Username</th>
|
||||||
@ -70,6 +79,25 @@
|
|||||||
</td>
|
</td>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div class="text-center mt-2">
|
||||||
|
<p>Total results: {{ this.banlist.pagination.totalResults | number }}</p>
|
||||||
|
<p>Page: {{ this.banlist.pagination.currentPage | number }} / {{ this.banlist.pagination.totalPages | number }}</p>
|
||||||
|
<div class="mb-2">
|
||||||
|
<button *ngIf="this.banlist.pagination.currentPage > 5" (click)="this.getBanlist(1)" style="margin-right: 5px">1</button>
|
||||||
|
<span *ngIf="this.banlist.pagination.currentPage > 6">... </span>
|
||||||
|
<button *ngFor="let page of [].constructor(Math.min(this.banlist.pagination.totalPages, 10)) | calculatePageRange:this.banlist.pagination.currentPage:this.banlist.pagination.totalPages; let i = index"
|
||||||
|
(click)="this.getBanlist(page)"
|
||||||
|
[disabled]="page == this.banlist.pagination.currentPage"
|
||||||
|
style="margin-right: 5px">
|
||||||
|
{{ page }}
|
||||||
|
</button>
|
||||||
|
<span *ngIf="this.banlist.pagination.currentPage < this.banlist.pagination.totalPages - 5">... </span>
|
||||||
|
<button *ngIf="this.banlist.pagination.currentPage < this.banlist.pagination.totalPages - 4" (click)="this.getBanlist(this.banlist.pagination.totalPages)" style="margin-right: 5px">{{ this.banlist.pagination.totalPages }}</button>
|
||||||
|
</div>
|
||||||
|
<button (click)="this.getBanlist(this.banlist.pagination.currentPage - 1)" [disabled]="this.banlist.pagination.currentPage == 1">← Previous</button>
|
||||||
|
<button (click)="this.getBanlist(this.banlist.pagination.currentPage + 1)" [disabled]="this.banlist.pagination.currentPage == this.banlist.pagination.totalPages" style="margin-left: 5px">Next →</button>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import {calculateTimeAgo, formatDuration} from "../format";
|
|||||||
import {RouterLink} from "@angular/router";
|
import {RouterLink} from "@angular/router";
|
||||||
import {CuteProgressbarComponent} from "../../corelib/components/cute-progressbar/cute-progressbar.component";
|
import {CuteProgressbarComponent} from "../../corelib/components/cute-progressbar/cute-progressbar.component";
|
||||||
import {CuteLoadingComponent} from "../../corelib/components/cute-loading/cute-loading.component";
|
import {CuteLoadingComponent} from "../../corelib/components/cute-loading/cute-loading.component";
|
||||||
|
import {DownloadFilesService} from "../../corelib/service/download-files.service";
|
||||||
|
import {CalculatePageRangePipe} from "../../corelib/calculate-page-range.pipe";
|
||||||
|
|
||||||
interface BanlistResponse {
|
interface BanlistResponse {
|
||||||
pagination: BanlistPagination;
|
pagination: BanlistPagination;
|
||||||
@ -41,7 +43,8 @@ interface BanlistEntry {
|
|||||||
DatePipe,
|
DatePipe,
|
||||||
DecimalPipe,
|
DecimalPipe,
|
||||||
CuteProgressbarComponent,
|
CuteProgressbarComponent,
|
||||||
CuteLoadingComponent
|
CuteLoadingComponent,
|
||||||
|
CalculatePageRangePipe
|
||||||
],
|
],
|
||||||
templateUrl: './banlist.component.html',
|
templateUrl: './banlist.component.html',
|
||||||
styleUrl: './banlist.component.css'
|
styleUrl: './banlist.component.css'
|
||||||
@ -51,15 +54,18 @@ export class BanlistComponent implements OnInit {
|
|||||||
isLoading = true;
|
isLoading = true;
|
||||||
banlist: BanlistResponse | null = null;
|
banlist: BanlistResponse | null = null;
|
||||||
|
|
||||||
constructor(private httpClient: HttpClient) { }
|
constructor(
|
||||||
|
private httpClient: HttpClient,
|
||||||
|
public downloadFilesService: DownloadFilesService
|
||||||
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.getBanlist();
|
this.getBanlist();
|
||||||
}
|
}
|
||||||
|
|
||||||
getBanlist(): void {
|
getBanlist(page: number = 1): void {
|
||||||
const body = {
|
const body = {
|
||||||
page: 1
|
page: page
|
||||||
}
|
}
|
||||||
this.httpClient.post<BanlistResponse>(`${environment.apiUrl}/banlist`, body).subscribe(response => {
|
this.httpClient.post<BanlistResponse>(`${environment.apiUrl}/banlist`, body).subscribe(response => {
|
||||||
this.banlist = response;
|
this.banlist = response;
|
||||||
@ -69,4 +75,5 @@ export class BanlistComponent implements OnInit {
|
|||||||
|
|
||||||
protected readonly calculateTimeAgo = calculateTimeAgo;
|
protected readonly calculateTimeAgo = calculateTimeAgo;
|
||||||
protected readonly formatDuration = formatDuration;
|
protected readonly formatDuration = formatDuration;
|
||||||
|
protected readonly Math = Math;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
<div class="main container">
|
<div class="main term" style="width: 100%">
|
||||||
|
|
||||||
<div class="subcontainer" style="width: 100%">
|
|
||||||
<div class="term" style="width: 100%">
|
|
||||||
|
|
||||||
<div style="overflow: hidden;">
|
<div style="overflow: hidden;">
|
||||||
<img src="assets/contribute.png" width="184" style="float: left; margin-right: 20px;">
|
<img src="assets/contribute.png" width="184" style="float: left; margin-right: 20px;">
|
||||||
@ -12,7 +9,7 @@
|
|||||||
<div class="text-center mt-2 mb-2">
|
<div class="text-center mt-2 mb-2">
|
||||||
<a href="https://patreon.com/nise_moe" target="_blank" class="btn btn-patreon">Become a Patreon</a>
|
<a href="https://patreon.com/nise_moe" target="_blank" class="btn btn-patreon">Become a Patreon</a>
|
||||||
</div>
|
</div>
|
||||||
<p>the money will be used to pay for the server hosting and development time.</p>
|
<p>the money will be used to pay for the server hosting and development costs.</p>
|
||||||
<table style="display: block;">
|
<table style="display: block;">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
@ -32,8 +29,4 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,11 +1,4 @@
|
|||||||
<div class="main term text-center statistics">
|
<div class="main container" style="width: 886px !important;">
|
||||||
Players: {{ this.statistics?.total_users | number }} | Beatmaps: {{ this.statistics?.total_beatmaps | number }} | Scores: {{ this.statistics?.total_scores | number }}
|
|
||||||
<ng-container *ngIf="this.statistics?.total_bans">
|
|
||||||
| <a [routerLink]="['/banlist']">Bans: {{ this.statistics?.total_bans | number }}</a>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="main container">
|
|
||||||
|
|
||||||
<div class="subcontainer">
|
<div class="subcontainer">
|
||||||
<div class="term">
|
<div class="term">
|
||||||
|
|||||||
@ -1,24 +1,14 @@
|
|||||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {Observable, Subscription} from "rxjs";
|
import {Subscription} from "rxjs";
|
||||||
import {environment} from "../../environments/environment";
|
import {environment} from "../../environments/environment";
|
||||||
import {LocalCacheService} from "../../corelib/service/local-cache.service";
|
|
||||||
import {RxStompService} from "../../corelib/stomp/stomp.service";
|
import {RxStompService} from "../../corelib/stomp/stomp.service";
|
||||||
import {Message} from "@stomp/stompjs/esm6";
|
import {Message} from "@stomp/stompjs/esm6";
|
||||||
import {ErrorDistribution, ReplayData, ReplayDataChart, ReplayDataSimilarScore} from "../replays";
|
import {ReplayData} from "../replays";
|
||||||
import {DecimalPipe, NgForOf, NgIf} from "@angular/common";
|
import {DecimalPipe, NgForOf, NgIf} from "@angular/common";
|
||||||
import {Router, RouterLink} from "@angular/router";
|
import {Router, RouterLink} from "@angular/router";
|
||||||
import {HttpClient} from "@angular/common/http";
|
import {HttpClient} from "@angular/common/http";
|
||||||
import {CuteLoadingComponent} from "../../corelib/components/cute-loading/cute-loading.component";
|
import {CuteLoadingComponent} from "../../corelib/components/cute-loading/cute-loading.component";
|
||||||
|
|
||||||
interface Statistics {
|
|
||||||
total_beatmaps: number;
|
|
||||||
total_users: number;
|
|
||||||
total_scores: number;
|
|
||||||
total_replay_scores: number;
|
|
||||||
total_replay_similarity: number;
|
|
||||||
total_bans: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AnalyzeReplayResponse {
|
interface AnalyzeReplayResponse {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
@ -41,13 +31,11 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
liveScores: ReplayData[] = [];
|
liveScores: ReplayData[] = [];
|
||||||
|
|
||||||
liveScoresSub: Subscription | undefined;
|
liveScoresSub: Subscription | undefined;
|
||||||
statistics: Statistics | null = null;
|
|
||||||
wantsConnection: boolean = true;
|
wantsConnection: boolean = true;
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private localCacheService: LocalCacheService,
|
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private rxStompService: RxStompService,
|
private rxStompService: RxStompService,
|
||||||
@ -63,10 +51,6 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
} else {
|
} else {
|
||||||
this.subscribe();
|
this.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getStatistics().subscribe((response: Statistics) => {
|
|
||||||
this.statistics = response;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private subscribe() {
|
private subscribe() {
|
||||||
@ -96,14 +80,6 @@ export class HomeComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatistics(): Observable<Statistics> {
|
|
||||||
return this.localCacheService.fetchData<Statistics>(
|
|
||||||
'statistics',
|
|
||||||
`${environment.apiUrl}/stats`,
|
|
||||||
60
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadReplay(event: any) {
|
uploadReplay(event: any) {
|
||||||
if (event.target.files.length <= 0) {
|
if (event.target.files.length <= 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1,7 +1,16 @@
|
|||||||
<div class="main term mb-2">
|
<div class="main term mb-2">
|
||||||
<div class="fade-stuff">
|
<div class="fade-stuff">
|
||||||
|
<h1 class="mb-4"><span class="text-muted">hi,</span> {{ this.userService.currentUser?.username }}</h1>
|
||||||
|
|
||||||
<h1 class="mb-4"># follow-list</h1>
|
<h1 class="mb-4"># follow-list</h1>
|
||||||
<table *ngIf="this.follows">
|
<ng-template #noFollows>
|
||||||
|
<div class="text-center">
|
||||||
|
<p>You are not following anyone!</p>
|
||||||
|
<p>You can follow users by going on their profile and clicking the <code>(+) Add follow</code> buttan.</p>
|
||||||
|
<p>Then, they'll appear here, and you'll be able to check if they've been banned or not.</p>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
<table *ngIf="this.follows && this.follows.follows.length > 0; else noFollows">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">Username</th>
|
<th colspan="2">Username</th>
|
||||||
@ -4,6 +4,8 @@ import {environment} from "../../environments/environment";
|
|||||||
import {JsonPipe, NgForOf, NgIf} from "@angular/common";
|
import {JsonPipe, NgForOf, NgIf} from "@angular/common";
|
||||||
import {calculateTimeAgo} from "../format";
|
import {calculateTimeAgo} from "../format";
|
||||||
import {RouterLink} from "@angular/router";
|
import {RouterLink} from "@angular/router";
|
||||||
|
import {UserService} from "../../corelib/service/user.service";
|
||||||
|
import {Title} from "@angular/platform-browser";
|
||||||
|
|
||||||
interface FollowsBanStatusResponse {
|
interface FollowsBanStatusResponse {
|
||||||
follows: FollowsBanStatusEntry[];
|
follows: FollowsBanStatusEntry[];
|
||||||
@ -18,7 +20,7 @@ interface FollowsBanStatusEntry {
|
|||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-follows',
|
selector: 'app-profile',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
JsonPipe,
|
JsonPipe,
|
||||||
@ -26,16 +28,21 @@ interface FollowsBanStatusEntry {
|
|||||||
NgIf,
|
NgIf,
|
||||||
RouterLink
|
RouterLink
|
||||||
],
|
],
|
||||||
templateUrl: './follows.component.html',
|
templateUrl: './profile.component.html',
|
||||||
styleUrl: './follows.component.css'
|
styleUrl: './profile.component.css'
|
||||||
})
|
})
|
||||||
export class FollowsComponent implements OnInit {
|
export class ProfileComponent implements OnInit {
|
||||||
|
|
||||||
follows: FollowsBanStatusResponse | null = null;
|
follows: FollowsBanStatusResponse | null = null;
|
||||||
|
|
||||||
constructor(private httpClient: HttpClient) { }
|
constructor(
|
||||||
|
private httpClient: HttpClient,
|
||||||
|
private title: Title,
|
||||||
|
public userService: UserService
|
||||||
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.title.setTitle(`hi, ${this.userService.currentUser!.username}`);
|
||||||
this.getFollows();
|
this.getFollows();
|
||||||
}
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user