added hide boosts, block domain, fix #487

This commit is contained in:
Nicolas Constant 2023-08-19 20:02:37 -04:00
parent a0cb240446
commit 8c9685045e
No known key found for this signature in database
GPG Key ID: 1E9F677FB01A5688
5 changed files with 157 additions and 12 deletions

View File

@ -27,7 +27,13 @@
<ng-template contextMenuItem (execute)="unmuteConversation()" *ngIf="statusWrapper && isOwnerSelected && displayedStatus.muted"> <ng-template contextMenuItem (execute)="unmuteConversation()" *ngIf="statusWrapper && isOwnerSelected && displayedStatus.muted">
Unmute conversation Unmute conversation
</ng-template> </ng-template>
<ng-template contextMenuItem divider="true"></ng-template> <ng-template contextMenuItem (execute)="hideBoosts()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.following && this.relationship.showing_reblogs">
Hide boosts from @{{ this.username }}
</ng-template>
<ng-template contextMenuItem (execute)="unhideBoosts()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.following && !this.relationship.showing_reblogs">
Unhide boosts from @{{ this.username }}
</ng-template>
<ng-template contextMenuItem divider="true" *ngIf="!isOwnerSelected"></ng-template>
<ng-template contextMenuItem (execute)="muteAccount()" *ngIf="!isOwnerSelected && this.relationship && !this.relationship.muting"> <ng-template contextMenuItem (execute)="muteAccount()" *ngIf="!isOwnerSelected && this.relationship && !this.relationship.muting">
Mute @{{ this.username }} Mute @{{ this.username }}
</ng-template> </ng-template>
@ -40,6 +46,14 @@
<ng-template contextMenuItem (execute)="unblockAccount()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.blocking"> <ng-template contextMenuItem (execute)="unblockAccount()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.blocking">
Unblock @{{ this.username }} Unblock @{{ this.username }}
</ng-template> </ng-template>
<ng-template contextMenuItem divider="true" *ngIf="!isOwnerSelected"></ng-template>
<ng-template contextMenuItem (execute)="blockDomain()" *ngIf="!isOwnerSelected && this.relationship && !this.relationship.domain_blocking">
Block domain {{ this.domain }}
</ng-template>
<ng-template contextMenuItem (execute)="unblockDomain()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.domain_blocking">
Unblock domain {{ this.domain }}
</ng-template>
<ng-template contextMenuItem divider="true" *ngIf="isOwnerSelected"></ng-template>
<ng-template contextMenuItem (execute)="pinOnProfile()" *ngIf="statusWrapper && isOwnerSelected && !displayedStatus.pinned && displayedStatus.visibility === 'public'"> <ng-template contextMenuItem (execute)="pinOnProfile()" *ngIf="statusWrapper && isOwnerSelected && !displayedStatus.pinned && displayedStatus.visibility === 'public'">
Pin on profile Pin on profile
</ng-template> </ng-template>

View File

@ -25,6 +25,7 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
private loadedAccounts: AccountInfo[]; private loadedAccounts: AccountInfo[];
displayedStatus: Status; displayedStatus: Status;
username: string; username: string;
domain: string;
isOwnerSelected: boolean; isOwnerSelected: boolean;
isEditingAvailable: boolean; isEditingAvailable: boolean;
@ -74,6 +75,7 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
} }
this.username = account.acct.split('@')[0]; this.username = account.acct.split('@')[0];
this.domain = account.acct.split('@')[1];
this.fullHandle = this.toolsService.getAccountFullHandle(account); this.fullHandle = this.toolsService.getAccountFullHandle(account);
} }
@ -167,6 +169,38 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
return false; return false;
} }
hideBoosts(): boolean {
const acc = this.toolsService.getSelectedAccounts()[0];
this.toolsService.findAccount(acc, this.fullHandle)
.then(async (target: Account) => {
const relationship = await this.mastodonService.hideBoosts(acc, target);
this.relationship = relationship;
this.relationshipChanged.next(relationship);
})
.catch(err => {
this.notificationService.notifyHttpError(err, acc);
});
return false;
}
unhideBoosts(): boolean {
const acc = this.toolsService.getSelectedAccounts()[0];
this.toolsService.findAccount(acc, this.fullHandle)
.then(async (target: Account) => {
const relationship = await this.mastodonService.unhideBoosts(acc, target);
this.relationship = relationship;
this.relationshipChanged.next(relationship);
})
.catch(err => {
this.notificationService.notifyHttpError(err, acc);
});
return false;
}
muteAccount(): boolean { muteAccount(): boolean {
const acc = this.toolsService.getSelectedAccounts()[0]; const acc = this.toolsService.getSelectedAccounts()[0];
@ -241,6 +275,37 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
return false; return false;
} }
blockDomain(): boolean {
const response = confirm(`Are you really sure you want to block the entire ${this.domain} domain? You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.`);
if (response) {
const acc = this.toolsService.getSelectedAccounts()[0];
this.mastodonService.blockDomain(acc, this.domain)
.then(_ => {
this.relationship.domain_blocking = true;
})
.catch(err => {
this.notificationService.notifyHttpError(err, acc);
});
}
return false;
}
unblockDomain(): boolean {
const acc = this.toolsService.getSelectedAccounts()[0];
this.mastodonService.blockDomain(acc, this.domain)
.then(_ => {
this.relationship.domain_blocking = false;
})
.catch(err => {
this.notificationService.notifyHttpError(err, acc);
});
return false;
}
muteConversation(): boolean { muteConversation(): boolean {
const selectedAccount = this.toolsService.getSelectedAccounts()[0]; const selectedAccount = this.toolsService.getSelectedAccounts()[0];

View File

@ -22,14 +22,14 @@ export class MastodonWrapperService {
private readonly mastodonService: MastodonService) { } private readonly mastodonService: MastodonService) { }
refreshAccountIfNeeded(accountInfo: AccountInfo): Promise<AccountInfo> { refreshAccountIfNeeded(accountInfo: AccountInfo): Promise<AccountInfo> {
if(this.refreshingToken[accountInfo.id]){ if (this.refreshingToken[accountInfo.id]) {
return this.refreshingToken[accountInfo.id]; return this.refreshingToken[accountInfo.id];
} }
let isExpired = false; let isExpired = false;
let storedAccountInfo = this.getStoreAccountInfo(accountInfo.id); let storedAccountInfo = this.getStoreAccountInfo(accountInfo.id);
if(!storedAccountInfo || !(storedAccountInfo.token)) if (!storedAccountInfo || !(storedAccountInfo.token))
return Promise.resolve(accountInfo); return Promise.resolve(accountInfo);
try { try {
@ -96,7 +96,7 @@ export class MastodonWrapperService {
return this.mastodonService.getInstance(instance); return this.mastodonService.getInstance(instance);
} }
translate(account: AccountInfo, statusId: string, lang: string): Promise<Translation>{ translate(account: AccountInfo, statusId: string, lang: string): Promise<Translation> {
return this.refreshAccountIfNeeded(account) return this.refreshAccountIfNeeded(account)
.then((refreshedAccount: AccountInfo) => { .then((refreshedAccount: AccountInfo) => {
return this.mastodonService.translate(refreshedAccount, statusId, lang); return this.mastodonService.translate(refreshedAccount, statusId, lang);
@ -146,7 +146,7 @@ export class MastodonWrapperService {
} }
search(account: AccountInfo, query: string, version: 'v1' | 'v2', resolve: boolean = false): Promise<Results> { search(account: AccountInfo, query: string, version: 'v1' | 'v2', resolve: boolean = false): Promise<Results> {
if(query.includes('twitter.com')){ if (query.includes('twitter.com')) {
query = this.processTwitterQuery(query); query = this.processTwitterQuery(query);
} }
@ -158,17 +158,17 @@ export class MastodonWrapperService {
private processTwitterQuery(query: string): string { private processTwitterQuery(query: string): string {
const settings = this.settingsService.getSettings(); const settings = this.settingsService.getSettings();
if(!settings.twitterBridgeInstance) return query; if (!settings.twitterBridgeInstance) return query;
let name; let name;
if(query.includes('twitter.com/')){ if (query.includes('twitter.com/')) {
console.log(query.replace('https://', '').replace('http://', '').split('/')); console.log(query.replace('https://', '').replace('http://', '').split('/'));
name = query.replace('https://', '').replace('http://', '').split('/')[1]; name = query.replace('https://', '').replace('http://', '').split('/')[1];
} }
if(query.includes('@twitter.com')){ if (query.includes('@twitter.com')) {
console.log(query.split('@')); console.log(query.split('@'));
name = query.split('@')[0]; name = query.split('@')[0];
if(name === '' || name == null){ if (name === '' || name == null) {
name = query.split('@')[1]; name = query.split('@')[1];
} }
} }
@ -208,7 +208,7 @@ export class MastodonWrapperService {
} }
searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> { searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> {
if(query.includes('twitter.com')){ if (query.includes('twitter.com')) {
query = this.processTwitterQuery(query); query = this.processTwitterQuery(query);
} }
@ -281,6 +281,20 @@ export class MastodonWrapperService {
}); });
} }
hideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
return this.refreshAccountIfNeeded(currentlyUsedAccount)
.then((refreshedAccount: AccountInfo) => {
return this.mastodonService.hideBoosts(refreshedAccount, account);
});
}
unhideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
return this.refreshAccountIfNeeded(currentlyUsedAccount)
.then((refreshedAccount: AccountInfo) => {
return this.mastodonService.unhideBoosts(refreshedAccount, account);
});
}
followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> { followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> {
return this.refreshAccountIfNeeded(currentlyUsedAccount) return this.refreshAccountIfNeeded(currentlyUsedAccount)
.then((refreshedAccount: AccountInfo) => { .then((refreshedAccount: AccountInfo) => {
@ -407,6 +421,20 @@ export class MastodonWrapperService {
}); });
} }
blockDomain(account: AccountInfo, domain: string): Promise<void> {
return this.refreshAccountIfNeeded(account)
.then((refreshedAccount: AccountInfo) => {
return this.mastodonService.blockDomain(refreshedAccount, domain);
});
}
unblockDomain(account: AccountInfo, domain: string): Promise<void> {
return this.refreshAccountIfNeeded(account)
.then((refreshedAccount: AccountInfo) => {
return this.mastodonService.unblockDomain(refreshedAccount, domain);
});
}
pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> { pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> {
return this.refreshAccountIfNeeded(account) return this.refreshAccountIfNeeded(account)
.then((refreshedAccount: AccountInfo) => { .then((refreshedAccount: AccountInfo) => {
@ -470,14 +498,14 @@ export class MastodonWrapperService {
}); });
} }
getFollowing(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> { getFollowing(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> {
return this.refreshAccountIfNeeded(account) return this.refreshAccountIfNeeded(account)
.then((refreshedAccount: AccountInfo) => { .then((refreshedAccount: AccountInfo) => {
return this.mastodonService.getFollowing(refreshedAccount, accountId, maxId, sinceId, limit); return this.mastodonService.getFollowing(refreshedAccount, accountId, maxId, sinceId, limit);
}); });
} }
getFollowers(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> { getFollowers(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> {
return this.refreshAccountIfNeeded(account) return this.refreshAccountIfNeeded(account)
.then((refreshedAccount: AccountInfo) => { .then((refreshedAccount: AccountInfo) => {
return this.mastodonService.getFollowers(refreshedAccount, accountId, maxId, sinceId, limit); return this.mastodonService.getFollowers(refreshedAccount, accountId, maxId, sinceId, limit);

View File

@ -357,6 +357,26 @@ export class MastodonService {
} }
hideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.follow}`.replace('{0}', account.id.toString());
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
let input = new FormData();
input.append('reblogs', 'false');
return this.httpClient.post<Relationship>(route, input, { headers: headers }).toPromise();
}
unhideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.follow}`.replace('{0}', account.id.toString());
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
let input = new FormData();
input.append('reblogs', 'true');
return this.httpClient.post<Relationship>(route, input, { headers: headers }).toPromise();
}
followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> { followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> {
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.followHashtag}`.replace('{0}', hashtag); const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.followHashtag}`.replace('{0}', hashtag);
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` }); const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
@ -524,6 +544,23 @@ export class MastodonService {
return this.httpClient.post<Relationship>(route, null, { headers: headers }).toPromise(); return this.httpClient.post<Relationship>(route, null, { headers: headers }).toPromise();
} }
blockDomain(account: AccountInfo, domain: string): Promise<void> {
let route = `https://${account.instance}${this.apiRoutes.blockDomain}`;
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
let input = new FormData();
input.append('domain', domain);
return this.httpClient.post<void>(route, input, { headers: headers }).toPromise();
}
unblockDomain(account: AccountInfo, domain: string): Promise<void> {
let route = `https://${account.instance}${this.apiRoutes.blockDomain}?domain=${domain}`;
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}`});
return this.httpClient.delete<void>(route, { headers: headers }).toPromise();
}
pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> { pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> {
let route = `https://${account.instance}${this.apiRoutes.pinStatus}`.replace('{0}', statusId.toString()); let route = `https://${account.instance}${this.apiRoutes.pinStatus}`.replace('{0}', statusId.toString());
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` }); const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });

View File

@ -12,6 +12,7 @@ export class ApiRoutes {
unfollow = '/api/v1/accounts/{0}/unfollow'; unfollow = '/api/v1/accounts/{0}/unfollow';
block = '/api/v1/accounts/{0}/block'; block = '/api/v1/accounts/{0}/block';
unblock = '/api/v1/accounts/{0}/unblock'; unblock = '/api/v1/accounts/{0}/unblock';
blockDomain = '/api/v1/domain_blocks';
mute = '/api/v1/accounts/{0}/mute'; mute = '/api/v1/accounts/{0}/mute';
unmute = '/api/v1/accounts/{0}/unmute'; unmute = '/api/v1/accounts/{0}/unmute';
muteStatus = '/api/v1/statuses/{0}/mute'; muteStatus = '/api/v1/statuses/{0}/mute';