Skip to content

Commit

Permalink
Merge pull request #11 from mvdicarlo/develop
Browse files Browse the repository at this point in the history
Merge v3.0.11
  • Loading branch information
mvdicarlo authored Jun 9, 2020
2 parents c778d19 + 9f42e0e commit 94dffd9
Show file tree
Hide file tree
Showing 16 changed files with 918 additions and 213 deletions.
656 changes: 455 additions & 201 deletions electron-app/package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions electron-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "postybirb-plus",
"version": "3.0.10",
"version": "3.0.11",
"description": "(ClientServer) PostyBirb is an application that helps artists post art and other multimedia to multiple websites more quickly.",
"main": "main.js",
"author": "Michael DiCarlo",
Expand Down Expand Up @@ -48,7 +48,7 @@
"class-validator": "^0.11.0",
"compression": "^1.7.4",
"electron-context-menu": "^0.15.2",
"electron-updater": "^4.2.0",
"electron-updater": "^4.3.1",
"electron-window-state": "^5.0.3",
"fs-extra": "^8.1.0",
"gif-frames": "^1.0.1",
Expand Down Expand Up @@ -91,8 +91,8 @@
"@types/set-cookie-parser": "0.0.6",
"@types/socket.io": "^2.1.4",
"@types/supertest": "^2.0.8",
"electron": "^7.2.1",
"electron-builder": "~22.3.2",
"electron": "^7.3.1",
"electron-builder": "~22.7.0",
"jest": "^24.9.0",
"prettier": "^1.18.2",
"supertest": "^4.0.2",
Expand Down
10 changes: 8 additions & 2 deletions electron-app/src/http/http.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface GetOptions {

interface PostOptions extends GetOptions {
data?: any;
type?: 'form' | 'multipart' | 'json';
type?: 'form' | 'multipart' | 'json' | 'function';
}

export interface HttpResponse<T> {
Expand Down Expand Up @@ -175,12 +175,14 @@ export default class Http {
opts.formData = options.data;
} else if (options.type === 'form') {
opts.form = options.data;
} else if (options.type === 'function') {
// Do nothing here
} else {
opts.body = options.data;
}

return new Promise(resolve => {
Http.Request[type](uri, opts, (error, response, body) => {
const request = Http.Request[type](uri, opts, (error, response, body) => {
const res: HttpResponse<T> = {
error,
response,
Expand All @@ -189,6 +191,10 @@ export default class Http {
};
resolve(res);
});

if (options.type === 'function' && options.data) {
options.data(request.form());
}
});
}
}
2 changes: 1 addition & 1 deletion electron-app/src/websites/custom/custom.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class Custom extends Website {
case 'bbcode':
return BBCodeParser.parse;
case 'html':
return HtmlParser.parse;
return undefined;
case 'md':
return MarkdownParser.parse;
case 'text':
Expand Down
19 changes: 19 additions & 0 deletions electron-app/src/websites/pillowfort/pillowfort.defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { PillowfortFileOptions, PillowfortNotificationOptions } from './pillowfort.interface';
import {
GenericDefaultFileOptions,
GenericDefaultNotificationOptions,
} from '../generic/generic.defaults';

export const PillowfortDefaultFileOptions: PillowfortFileOptions = {
...GenericDefaultFileOptions,
privacy: 'public',
allowComments: true,
allowReblogging: true,
};

export const PillowfortDefaultNotificationOptions: PillowfortNotificationOptions = {
...GenericDefaultNotificationOptions,
privacy: 'public',
allowComments: true,
allowReblogging: true,
};
16 changes: 16 additions & 0 deletions electron-app/src/websites/pillowfort/pillowfort.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {
DefaultFileOptions,
DefaultOptions,
} from '../../submission/submission-part/interfaces/default-options.interface';

export interface PillowfortFileOptions extends DefaultFileOptions {
privacy: string;
allowComments: boolean;
allowReblogging: boolean;
}

export interface PillowfortNotificationOptions extends DefaultOptions {
privacy: string;
allowComments: boolean;
allowReblogging: boolean;
}
8 changes: 8 additions & 0 deletions electron-app/src/websites/pillowfort/pillowfort.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { Pillowfort } from './pillowfort.service';

@Module({
providers: [Pillowfort],
exports: [Pillowfort],
})
export class PillowfortModule {}
207 changes: 207 additions & 0 deletions electron-app/src/websites/pillowfort/pillowfort.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { Injectable } from '@nestjs/common';
import { Website } from '../website.base';
import {
PillowfortDefaultNotificationOptions,
PillowfortDefaultFileOptions,
} from './pillowfort.defaults';
import UserAccountEntity from 'src/account/models/user-account.entity';
import { LoginResponse } from '../interfaces/login-response.interface';
import Http from 'src/http/http.util';
import { FileRecord } from 'src/submission/file-submission/interfaces/file-record.interface';
import { PillowfortFileOptions, PillowfortNotificationOptions } from './pillowfort.interface';
import { FileSubmission } from 'src/submission/file-submission/interfaces/file-submission.interface';
import { SubmissionPart } from 'src/submission/submission-part/interfaces/submission-part.interface';
import { DefaultOptions } from 'src/submission/submission-part/interfaces/default-options.interface';
import { ValidationParts } from 'src/submission/validator/interfaces/validation-parts.interface';
import WebsiteValidator from 'src/utils/website-validator.util';
import { CancellationToken } from 'src/submission/post/cancellation/cancellation-token';
import { Submission } from 'src/submission/interfaces/submission.interface';
import { PostResponse } from 'src/submission/post/interfaces/post-response.interface';
import HtmlParserUtil from 'src/utils/html-parser.util';
import { SubmissionRating } from 'src/submission/enums/submission-rating.enum';
import { FilePostData, PostFile } from 'src/submission/post/interfaces/file-post-data.interface';
import { PostData } from 'src/submission/post/interfaces/post-data.interface';
import * as FormData from 'form-data';
import BrowserWindowUtil from 'src/utils/browser-window.util';

@Injectable()
export class Pillowfort extends Website {
readonly BASE_URL = 'https://www.pillowfort.social';
readonly acceptsAdditionalFiles = true;
readonly acceptsFiles = ['png', 'jpeg', 'jpg', 'gif'];
readonly fileSubmissionOptions = PillowfortDefaultFileOptions;
readonly notificationSubmissionOptions = PillowfortDefaultNotificationOptions;
readonly usernameShortcuts = [
{
key: 'pf',
url: 'https://www.pillowfort.social/$1',
},
];

async checkLoginStatus(data: UserAccountEntity): Promise<LoginResponse> {
const status: LoginResponse = { loggedIn: false, username: null };
const res = await Http.get<string>(this.BASE_URL, data._id);
await BrowserWindowUtil.getPage(data._id, this.BASE_URL);
if (res.body.includes('/signout')) {
status.loggedIn = true;
status.username = res.body.match(/value="current_user">(.*?)</)[1];
}
return status;
}

parseDescription(text: string) {
return text;
}

getScalingOptions(file: FileRecord) {
return undefined;
}

private async uploadImage(
photo: PostFile,
profileId: string,
auth: string,
): Promise<{ full_image: string; small_image: string }> {
const upload = await Http.post<any>(`${this.BASE_URL}/image_upload`, profileId, {
type: 'multipart',
data: {
file_name: photo.options.filename,
photo,
},
requestOptions: { json: true },
headers: {
'X-CSRF-Token': auth,
},
});

this.verifyResponse(upload, 'Image upload verify');
return upload.body;
}

async postFileSubmission(
cancellationToken: CancellationToken,
data: FilePostData<PillowfortFileOptions>,
): Promise<PostResponse> {
const page = await Http.get<string>(`${this.BASE_URL}/posts/new`, data.part.accountId);
this.verifyResponse(page, 'Get form page');

const form: any = {
authenticity_token: HtmlParserUtil.getInputValue(page.body, 'authenticity_token'),
utf8: '✓',
post_to: 'current_user',
post_type: 'picture',
title: data.title,
content: `<p>${data.description}</p>`,
privacy: data.options.privacy,
tags: this.formatTags(data.tags),
commit: 'Submit',
};

if (data.options.allowReblogging) {
form.rebloggable = 'on';
}
if (!data.options.allowComments) {
form.commentable = 'on';
}
if (data.rating !== SubmissionRating.GENERAL) {
form.nsfw = 'on';
}

const uploads = await Promise.all(
[data.primary, ...data.additional]
.map(f => f.file)
.map(f => this.uploadImage(f, data.part.accountId, form.authenticity_token)),
);

this.checkCancelled(cancellationToken);
const post = await Http.post<string>(`${this.BASE_URL}/posts/create`, data.part.accountId, {
type: 'function',
data: (fd: FormData) => {
Object.entries(form).forEach(([key, value]) => {
fd.append(key, value);
});

uploads.forEach((upload, i) => {
fd.append('picture[][pic_url]', upload.full_image);
fd.append('picture[][small_image_url]', upload.small_image);
fd.append('picture[][b2_lg_url]', '');
fd.append('picture[][b2_sm_url]', '');
fd.append('picture[][row]', `${i + 1}`);
fd.append('picture[][col]', '0');
});
},
});

this.verifyResponse(post, 'Verify post success');
if (post.response.statusCode === 200) {
return this.createPostResponse({});
}

return Promise.reject(this.createPostResponse({ additionalInfo: post.body }));
}

async postNotificationSubmission(
cancellationToken: CancellationToken,
data: PostData<Submission, PillowfortNotificationOptions>,
): Promise<PostResponse> {
const page = await Http.get<string>(`${this.BASE_URL}/posts/new`, data.part.accountId);
this.verifyResponse(page, 'Get form page');

const form: any = {
authenticity_token: HtmlParserUtil.getInputValue(page.body, 'authenticity_token'),
utf8: '✓',
post_to: 'current_user',
post_type: 'text',
title: data.title,
content: `<p>${data.description}</p>`,
privacy: data.options.privacy,
tags: this.formatTags(data.tags),
commit: 'Submit',
};

if (data.options.allowReblogging) {
form.rebloggable = 'on';
}
if (!data.options.allowComments) {
form.commentable = 'on';
}
if (data.rating !== SubmissionRating.GENERAL) {
form.nsfw = 'on';
}

this.checkCancelled(cancellationToken);
const post = await Http.post<string>(`${this.BASE_URL}/posts/create`, data.part.accountId, {
type: 'multipart',
data: form,
});

this.verifyResponse(post, 'Verify post success');
if (post.response.statusCode === 200) {
return this.createPostResponse({});
}

return Promise.reject(this.createPostResponse({ additionalInfo: post.body }));
}

formatTags(tags: string[]) {
return tags.join(', ');
}

validateFileSubmission(
submission: FileSubmission,
submissionPart: SubmissionPart<PillowfortFileOptions>,
defaultPart: SubmissionPart<DefaultOptions>,
): ValidationParts {
const problems: string[] = [];
const warnings: string[] = [];
const isAutoscaling: boolean = submissionPart.data.autoScale;

if (!WebsiteValidator.supportsFileType(submission.primary, this.acceptsFiles)) {
problems.push(
`Does not support file format: (${submission.primary.name}) ${submission.primary.mimetype}.`,
);
}

return { problems, warnings };
}
}
2 changes: 1 addition & 1 deletion electron-app/src/websites/so-furry/so-furry.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { GenericAccountProp } from '../generic/generic-account-props.enum';
@Injectable()
export class SoFurry extends Website {
readonly BASE_URL: string = 'https://www.sofurry.com';
readonly acceptsFiles: string[] = ['png', 'jpeg', 'jpg', 'gif', 'swf', 'txt', 'mp3'];
readonly acceptsFiles: string[] = ['png', 'jpeg', 'jpg', 'gif', 'swf', 'txt', 'mp3', 'mp4'];

readonly fileSubmissionOptions: SoFurryFileOptions = SoFurryDefaultFileOptions;

Expand Down
2 changes: 2 additions & 0 deletions electron-app/src/websites/website-provider.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { Tumblr } from './tumblr/tumblr.service';
import { DeviantArt } from './deviant-art/deviant-art.service';
import { Mastodon } from './mastodon/mastodon.service';
import { Twitter } from './twitter/twitter.service';
import { Pillowfort } from './pillowfort/pillowfort.service';

@Injectable()
export class WebsiteProvider {
Expand Down Expand Up @@ -57,6 +58,7 @@ export class WebsiteProvider {
readonly deviantArt: DeviantArt,
readonly mastodon: Mastodon,
readonly twitter: Twitter,
readonly pillowfort: Pillowfort
) {
this.websiteModules = [...arguments].filter(arg => arg instanceof Website);
this.websiteModules.forEach(
Expand Down
2 changes: 2 additions & 0 deletions electron-app/src/websites/websites.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { TumblrModule } from './tumblr/tumblr.module';
import { DeviantArtModule } from './deviant-art/deviant-art.module';
import { MastodonModule } from './mastodon/mastodon.module';
import { TwitterModule } from './twitter/twitter.module';
import { PillowfortModule } from './pillowfort/pillowfort.module';

@Module({
controllers: [WebsitesController],
Expand Down Expand Up @@ -58,6 +59,7 @@ import { TwitterModule } from './twitter/twitter.module';
DeviantArtModule,
MastodonModule,
TwitterModule,
PillowfortModule,
],
})
export class WebsitesModule {}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "postybirb-plus",
"version": "3.0.10",
"version": "3.0.11",
"description": "PostyBirb is an application that helps artists post art and other multimedia to multiple websites more quickly..",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "postybirb-ui",
"version": "3.0.10",
"version": "3.0.11",
"license": "BSD-3-Clause",
"private": true,
"Author": "Michael DiCarlo",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ export default class DescriptionInput extends React.Component<Props, State> {
'Paragraph=p;Header 1=h1;Header 2=h2;Header 3=h3;Header 4=h4;Header 5=h5;Header 6=h6',
content_style: 'p {margin: 0}',
height: 200,
plugins: 'autoresize autolink link preview paste hr template help code',
plugins: 'autoresize autolink link preview paste hr template help code lists',
menubar: 'file edit insert view tools help',
toolbar:
'newdocument undo redo | formatselect removeformat | link unlink hr | bold italic underline strikethrough forecolor | alignleft aligncenter alignright | code template help',
'newdocument undo redo | formatselect removeformat | link unlink hr | bold italic underline strikethrough forecolor | alignleft aligncenter alignright | bullist | code template help',
templates: [],
formats: {
underline: { inline: 'u', exact: true },
Expand Down
Loading

0 comments on commit 94dffd9

Please sign in to comment.