initial commit
This commit is contained in:
1
projects/mastodon-api/src/lib/interfaces/interfaces.ts
Normal file
1
projects/mastodon-api/src/lib/interfaces/interfaces.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './public/public';
|
||||
20
projects/mastodon-api/src/lib/interfaces/public/account.ts
Normal file
20
projects/mastodon-api/src/lib/interfaces/public/account.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {List} from "./list";
|
||||
|
||||
export interface Field {
|
||||
name: string;
|
||||
value: string;
|
||||
verified_at: Date;
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
id: string;
|
||||
username: string;
|
||||
acct: string;
|
||||
url: string;
|
||||
displayName: string;
|
||||
note: string;
|
||||
avatar: string;
|
||||
avatarStatic: string;
|
||||
fields: Field[];
|
||||
lists: List[];
|
||||
}
|
||||
8
projects/mastodon-api/src/lib/interfaces/public/list.ts
Normal file
8
projects/mastodon-api/src/lib/interfaces/public/list.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import {Account} from "./account";
|
||||
|
||||
export interface List {
|
||||
id: string;
|
||||
title: string;
|
||||
repliesPolicy: string;
|
||||
accounts: Account[]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './account';
|
||||
export * from './list';
|
||||
export * from './registered_app';
|
||||
export * from './user_account';
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface RegisteredApp{
|
||||
id: string;
|
||||
name: string;
|
||||
website: string;
|
||||
redirectUri: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
vapidKey: string;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface UserAccount {
|
||||
id: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface GetAccessTokenResponse {
|
||||
access_token: string;
|
||||
token_type: string;
|
||||
scope: string;
|
||||
created_at: Date;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export interface Field {
|
||||
name: string;
|
||||
value: string;
|
||||
verified_at: Date;
|
||||
}
|
||||
export interface GetAccountResponse {
|
||||
id: string;
|
||||
username: string;
|
||||
acct: string;
|
||||
url: string;
|
||||
display_name: string;
|
||||
note: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
fields: Field[];
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import {GetAccountResponse} from "./get_account_response";
|
||||
|
||||
export interface GetListsResponse {
|
||||
id: string;
|
||||
title: string;
|
||||
repliesPolicy: string;
|
||||
accounts: GetAccountResponse[]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface RegisterAppResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
website: string;
|
||||
redirect_uri: string;
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
vapid_key: string;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface VerifyCredentialsResponse {
|
||||
id: string;
|
||||
}
|
||||
21
projects/mastodon-api/src/lib/mastodon-api.module.ts
Normal file
21
projects/mastodon-api/src/lib/mastodon-api.module.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import {ModuleWithProviders, NgModule} from '@angular/core';
|
||||
import {MastodonApiListsService} from "./services/mastodon-api-lists.service";
|
||||
import {MastodonApiAuthenticationService} from "./services/mastodon-api-authentication.service";
|
||||
import {HttpClientModule} from "@angular/common/http";
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
HttpClientModule
|
||||
],
|
||||
exports: []
|
||||
})
|
||||
export class MastodonApiModule {
|
||||
static forRoot(): ModuleWithProviders<MastodonApiModule> {
|
||||
return {
|
||||
ngModule: MastodonApiModule,
|
||||
providers: [MastodonApiListsService, MastodonApiAuthenticationService]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {MastodonApiService} from "./mastodon-api.service";
|
||||
import {map, Observable} from "rxjs";
|
||||
import {GetAccountResponse} from "../interfaces/responses/get_account_response";
|
||||
import {Account} from "../interfaces/public/account";
|
||||
import {HttpResponse} from "@angular/common/http";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MastodonApiAccountsService {
|
||||
|
||||
constructor(private mastodonApiService: MastodonApiService) {
|
||||
}
|
||||
|
||||
getFollowingsForAccount(instanceName: string, accessToken: string, accountId: string, url: string = ''): Observable<[nextLink: string, accounts: Account[]]> {
|
||||
if (url === '') {
|
||||
url = `https://${instanceName}/api/v1/accounts/${accountId}/following?limit=80`;
|
||||
}
|
||||
return this.mastodonApiService
|
||||
.getAuthenticatedWithResponseHeaders<GetAccountResponse[]>(url, accessToken)
|
||||
.pipe(
|
||||
map((response) => {
|
||||
const links = response.headers.get('link');
|
||||
let rel = '';
|
||||
let nextUrl = '';
|
||||
if (links) {
|
||||
const nextLink = links!.split(',')[0];
|
||||
rel = nextLink.split(';')[1].replace(' rel="', '').replace('"', '');
|
||||
nextUrl = nextLink.split(';')[0].replace('<', '').replace('>', '');
|
||||
}
|
||||
|
||||
const accounts = response.body!.map((response) => {
|
||||
return <Account>{
|
||||
id: response.id,
|
||||
username: response.username,
|
||||
acct: response.acct,
|
||||
displayName: response.display_name,
|
||||
note: response.note,
|
||||
url: response.url,
|
||||
avatar: response.avatar,
|
||||
avatarStatic: response.avatar_static,
|
||||
fields: response.fields,
|
||||
};
|
||||
});
|
||||
return [rel === 'next' ? nextUrl : '', accounts];
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {map, Observable} from "rxjs";
|
||||
import {RegisterAppResponse} from "../interfaces/responses/register_app_response";
|
||||
import {GetAccessTokenResponse} from "../interfaces/responses/get_access_token_response";
|
||||
import {VerifyCredentialsResponse} from "../interfaces/responses/verify_credentials_response";
|
||||
import {MastodonApiService} from "./mastodon-api.service";
|
||||
import {RegisteredApp} from "../interfaces/public/registered_app";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MastodonApiAuthenticationService {
|
||||
|
||||
constructor(private mastodonApiService: MastodonApiService) {
|
||||
}
|
||||
|
||||
createApp(instance: string, clientName: string, redirectUrl: string, website: string): Observable<RegisteredApp> {
|
||||
const scopes = ['read', 'write']; // no 'follow'
|
||||
|
||||
const parameters: {
|
||||
client_name: string,
|
||||
redirect_uris: string,
|
||||
scopes: string,
|
||||
website: string
|
||||
} = {
|
||||
client_name: clientName,
|
||||
redirect_uris: redirectUrl,
|
||||
scopes: scopes.join(' '),
|
||||
website
|
||||
}
|
||||
const url = `https://${instance}/api/v1/apps`;
|
||||
return this.mastodonApiService
|
||||
.post<RegisterAppResponse>(url, parameters)
|
||||
.pipe(map((response) => {
|
||||
return <RegisteredApp>{
|
||||
id: response.id,
|
||||
name: response.name,
|
||||
website: response.website,
|
||||
redirectUri: response.redirect_uri,
|
||||
clientId: response.client_id,
|
||||
clientSecret: response.client_secret,
|
||||
vapidKey: response.vapid_key,
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
authorizeUser(instance: string, clientId: string, redirectUrl: string) {
|
||||
const parameters = [
|
||||
['response_type', 'code'].join("="),
|
||||
['scope', 'read write'].join("="),
|
||||
['client_id', clientId].join("="),
|
||||
['redirect_uri', redirectUrl].join("="),
|
||||
].join("&");
|
||||
window.location.href = `https://${instance}/oauth/authorize?${parameters}`;
|
||||
}
|
||||
|
||||
verifyCredentials(instance: string, accessToken: string): Observable<string> {
|
||||
const url = `https://${instance}/api/v1/accounts/verify_credentials`;
|
||||
return this.mastodonApiService
|
||||
.getAuthenticated<VerifyCredentialsResponse>(url, accessToken)
|
||||
.pipe(map((response) => response.id));
|
||||
|
||||
}
|
||||
|
||||
getAccessToken(instanceName: string, clientId: string, clientSecret: string, redirectUrl: string, code: string): Observable<string> {
|
||||
const parameters: {
|
||||
client_id: string,
|
||||
client_secret: string,
|
||||
redirect_uri: string,
|
||||
grant_type: string,
|
||||
code: string,
|
||||
scope: string
|
||||
} = {
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
redirect_uri: redirectUrl,
|
||||
grant_type: 'authorization_code',
|
||||
code: code,
|
||||
scope: 'read write'
|
||||
}
|
||||
const url = `https://${instanceName}/oauth/token`;
|
||||
return this.mastodonApiService
|
||||
.post<GetAccessTokenResponse>(url, parameters)
|
||||
.pipe(map((response) => response.access_token));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {concatMap, from, map, mergeAll, mergeMap, Observable, reduce, switchMap, tap, toArray} from "rxjs";
|
||||
import {VerifyCredentialsResponse} from "../interfaces/responses/verify_credentials_response";
|
||||
import {MastodonApiService} from "./mastodon-api.service";
|
||||
import {GetListsResponse} from "../interfaces/responses/get_lists_response";
|
||||
import {GetAccountResponse} from "../interfaces/responses/get_account_response";
|
||||
import {List} from "../interfaces/public/list";
|
||||
import {Account} from "../interfaces/public/account";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MastodonApiListsService {
|
||||
|
||||
constructor(private mastodonApiService: MastodonApiService) {
|
||||
}
|
||||
|
||||
getLists(instanceName: string, accessToken: string): Observable<List[]> {
|
||||
const url = `https://${instanceName}/api/v1/lists`;
|
||||
return this.mastodonApiService
|
||||
.getAuthenticated<GetListsResponse[]>(url, accessToken)
|
||||
.pipe(map((responses) => {
|
||||
return responses.map((response) => {
|
||||
return <List>{
|
||||
id: response.id,
|
||||
title: response.title,
|
||||
repliesPolicy: response.repliesPolicy,
|
||||
}
|
||||
})
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getAccountsForList(instanceName: string, accessToken: string, listId: string, url: string = ''): Observable<[nextLink: string, accounts: Account[]]> {
|
||||
if (url === '') {
|
||||
url = `https://${instanceName}/api/v1/lists/${listId}/accounts`;
|
||||
}
|
||||
return this.mastodonApiService
|
||||
.getAuthenticatedWithResponseHeaders<GetAccountResponse[]>(url, accessToken)
|
||||
.pipe(map(response => {
|
||||
const links = response.headers.get('link');
|
||||
let rel = '';
|
||||
let nextUrl = '';
|
||||
if (links) {
|
||||
const nextLink = links!.split(',')[0];
|
||||
rel = nextLink.split(';')[1].replace(' rel="', '').replace('"', '');
|
||||
nextUrl = nextLink.split(';')[0].replace('<', '').replace('>', '');
|
||||
}
|
||||
const accounts = response!.body!.map((response) => {
|
||||
return <Account>{
|
||||
id: response.id,
|
||||
username: response.username,
|
||||
acct: response.acct,
|
||||
displayName: response.display_name,
|
||||
note: response.note,
|
||||
url: response.url,
|
||||
avatar: response.avatar,
|
||||
avatarStatic: response.avatar_static,
|
||||
fields: response.fields,
|
||||
};
|
||||
});
|
||||
return [rel === 'next' ? nextUrl : '', accounts];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
addAccountToList(instanceName: string, accessToken: string, listId: string, accountId: string) {
|
||||
const url = `https://${instanceName}/api/v1/lists/${listId}/accounts`;
|
||||
return this.mastodonApiService
|
||||
.postAuthenticated(url, {account_ids: [accountId]}, accessToken);
|
||||
}
|
||||
|
||||
removeAccountFromList(instanceName: string, accessToken: string, listId: string, accountId: string) {
|
||||
const url = `https://${instanceName}/api/v1/lists/${listId}/accounts`;
|
||||
return this.mastodonApiService
|
||||
.deleteAuthenticated(url, {account_ids: [accountId]}, accessToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {Observable} from "rxjs";
|
||||
import {HttpClient, HttpHeaders, HttpResponse} from "@angular/common/http";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MastodonApiService {
|
||||
constructor(private httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
get<T>(url: string) {
|
||||
return this.httpClient.get<T>(url);
|
||||
}
|
||||
|
||||
getAuthenticated<T>(url: string, accessToken: string): Observable<T> {
|
||||
const reqHeader = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
});
|
||||
return this.httpClient.get<T>(url, {headers: reqHeader});
|
||||
}
|
||||
|
||||
getAuthenticatedWithResponseHeaders<T>(url: string, accessToken: string): Observable<HttpResponse<T>> {
|
||||
const reqHeader = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
});
|
||||
return this.httpClient.get<T>(url, {headers: reqHeader, observe: 'response'});
|
||||
}
|
||||
|
||||
post<T>(url: string, parameters: object) {
|
||||
return this.httpClient.post<T>(url, parameters);
|
||||
}
|
||||
|
||||
postAuthenticated(url: string, body: { account_ids: string[] }, accessToken: string) {
|
||||
const reqHeader = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
});
|
||||
return this.httpClient.post(url, body, {headers: reqHeader});
|
||||
}
|
||||
|
||||
deleteAuthenticated(url: string, body: { account_ids: string[] }, accessToken: string) {
|
||||
const reqHeader = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + accessToken
|
||||
});
|
||||
return this.httpClient.delete(url, {headers: reqHeader, body});
|
||||
}
|
||||
}
|
||||
4
projects/mastodon-api/src/lib/services/services.ts
Normal file
4
projects/mastodon-api/src/lib/services/services.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './mastodon-api.service';
|
||||
export * from './mastodon-api-accounts.service';
|
||||
export * from './mastodon-api-authentication.service';
|
||||
export * from './mastodon-api-lists.service';
|
||||
6
projects/mastodon-api/src/public-api.ts
Normal file
6
projects/mastodon-api/src/public-api.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Public API Surface of mastodon-api
|
||||
*/
|
||||
|
||||
export * from './lib/services/services';
|
||||
export * from './lib/interfaces/interfaces';
|
||||
Reference in New Issue
Block a user