diff --git a/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.html b/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.html index 3b49e8a7..8e252e49 100644 --- a/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.html +++ b/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.html @@ -27,7 +27,13 @@ Unmute conversation - + + Hide boosts from @{{ this.username }} + + + Unhide boosts from @{{ this.username }} + + Mute @{{ this.username }} @@ -40,6 +46,14 @@ Unblock @{{ this.username }} + + + Block domain {{ this.domain }} + + + Unblock domain {{ this.domain }} + + Pin on profile diff --git a/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.ts b/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.ts index f09e1cf4..20bb9a5b 100644 --- a/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.ts +++ b/src/app/components/stream/status/action-bar/status-user-context-menu/status-user-context-menu.component.ts @@ -25,6 +25,7 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy { private loadedAccounts: AccountInfo[]; displayedStatus: Status; username: string; + domain: string; isOwnerSelected: boolean; isEditingAvailable: boolean; @@ -74,6 +75,7 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy { } this.username = account.acct.split('@')[0]; + this.domain = account.acct.split('@')[1]; this.fullHandle = this.toolsService.getAccountFullHandle(account); } @@ -167,6 +169,38 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy { 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 { const acc = this.toolsService.getSelectedAccounts()[0]; @@ -241,6 +275,37 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy { 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 { const selectedAccount = this.toolsService.getSelectedAccounts()[0]; diff --git a/src/app/services/mastodon-wrapper.service.ts b/src/app/services/mastodon-wrapper.service.ts index 38717d37..d33517b8 100644 --- a/src/app/services/mastodon-wrapper.service.ts +++ b/src/app/services/mastodon-wrapper.service.ts @@ -22,14 +22,14 @@ export class MastodonWrapperService { private readonly mastodonService: MastodonService) { } refreshAccountIfNeeded(accountInfo: AccountInfo): Promise { - if(this.refreshingToken[accountInfo.id]){ + if (this.refreshingToken[accountInfo.id]) { return this.refreshingToken[accountInfo.id]; } let isExpired = false; let storedAccountInfo = this.getStoreAccountInfo(accountInfo.id); - if(!storedAccountInfo || !(storedAccountInfo.token)) + if (!storedAccountInfo || !(storedAccountInfo.token)) return Promise.resolve(accountInfo); try { @@ -96,7 +96,7 @@ export class MastodonWrapperService { return this.mastodonService.getInstance(instance); } - translate(account: AccountInfo, statusId: string, lang: string): Promise{ + translate(account: AccountInfo, statusId: string, lang: string): Promise { return this.refreshAccountIfNeeded(account) .then((refreshedAccount: AccountInfo) => { 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 { - if(query.includes('twitter.com')){ + if (query.includes('twitter.com')) { query = this.processTwitterQuery(query); } @@ -158,17 +158,17 @@ export class MastodonWrapperService { private processTwitterQuery(query: string): string { const settings = this.settingsService.getSettings(); - if(!settings.twitterBridgeInstance) return query; + if (!settings.twitterBridgeInstance) return query; let name; - if(query.includes('twitter.com/')){ + if (query.includes('twitter.com/')) { console.log(query.replace('https://', '').replace('http://', '').split('/')); name = query.replace('https://', '').replace('http://', '').split('/')[1]; } - if(query.includes('@twitter.com')){ + if (query.includes('@twitter.com')) { console.log(query.split('@')); name = query.split('@')[0]; - if(name === '' || name == null){ + if (name === '' || name == null) { 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 { - if(query.includes('twitter.com')){ + if (query.includes('twitter.com')) { query = this.processTwitterQuery(query); } @@ -281,6 +281,20 @@ export class MastodonWrapperService { }); } + hideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise { + return this.refreshAccountIfNeeded(currentlyUsedAccount) + .then((refreshedAccount: AccountInfo) => { + return this.mastodonService.hideBoosts(refreshedAccount, account); + }); + } + + unhideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise { + return this.refreshAccountIfNeeded(currentlyUsedAccount) + .then((refreshedAccount: AccountInfo) => { + return this.mastodonService.unhideBoosts(refreshedAccount, account); + }); + } + followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise { return this.refreshAccountIfNeeded(currentlyUsedAccount) .then((refreshedAccount: AccountInfo) => { @@ -407,6 +421,20 @@ export class MastodonWrapperService { }); } + blockDomain(account: AccountInfo, domain: string): Promise { + return this.refreshAccountIfNeeded(account) + .then((refreshedAccount: AccountInfo) => { + return this.mastodonService.blockDomain(refreshedAccount, domain); + }); + } + + unblockDomain(account: AccountInfo, domain: string): Promise { + return this.refreshAccountIfNeeded(account) + .then((refreshedAccount: AccountInfo) => { + return this.mastodonService.unblockDomain(refreshedAccount, domain); + }); + } + pinOnProfile(account: AccountInfo, statusId: string): Promise { return this.refreshAccountIfNeeded(account) .then((refreshedAccount: AccountInfo) => { @@ -470,14 +498,14 @@ export class MastodonWrapperService { }); } - getFollowing(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise { + getFollowing(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise { return this.refreshAccountIfNeeded(account) .then((refreshedAccount: AccountInfo) => { return this.mastodonService.getFollowing(refreshedAccount, accountId, maxId, sinceId, limit); }); } - getFollowers(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise { + getFollowers(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise { return this.refreshAccountIfNeeded(account) .then((refreshedAccount: AccountInfo) => { return this.mastodonService.getFollowers(refreshedAccount, accountId, maxId, sinceId, limit); diff --git a/src/app/services/mastodon.service.ts b/src/app/services/mastodon.service.ts index e4ce63b2..cc69ce0f 100644 --- a/src/app/services/mastodon.service.ts +++ b/src/app/services/mastodon.service.ts @@ -357,6 +357,26 @@ export class MastodonService { } + hideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise { + 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(route, input, { headers: headers }).toPromise(); + } + + unhideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise { + 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(route, input, { headers: headers }).toPromise(); + } + followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise { const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.followHashtag}`.replace('{0}', hashtag); const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` }); @@ -524,6 +544,23 @@ export class MastodonService { return this.httpClient.post(route, null, { headers: headers }).toPromise(); } + blockDomain(account: AccountInfo, domain: string): Promise { + 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(route, input, { headers: headers }).toPromise(); + } + + unblockDomain(account: AccountInfo, domain: string): Promise { + let route = `https://${account.instance}${this.apiRoutes.blockDomain}?domain=${domain}`; + const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}`}); + + return this.httpClient.delete(route, { headers: headers }).toPromise(); + } + pinOnProfile(account: AccountInfo, statusId: string): Promise { let route = `https://${account.instance}${this.apiRoutes.pinStatus}`.replace('{0}', statusId.toString()); const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` }); diff --git a/src/app/services/models/api.settings.ts b/src/app/services/models/api.settings.ts index 3a204317..6a36c09f 100644 --- a/src/app/services/models/api.settings.ts +++ b/src/app/services/models/api.settings.ts @@ -12,6 +12,7 @@ export class ApiRoutes { unfollow = '/api/v1/accounts/{0}/unfollow'; block = '/api/v1/accounts/{0}/block'; unblock = '/api/v1/accounts/{0}/unblock'; + blockDomain = '/api/v1/domain_blocks'; mute = '/api/v1/accounts/{0}/mute'; unmute = '/api/v1/accounts/{0}/unmute'; muteStatus = '/api/v1/statuses/{0}/mute';