summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ansible/templates/nginx.conf10
-rw-r--r--docker/dev/docker-compose.yml7
-rw-r--r--docker/prod/docker-compose.yml9
-rw-r--r--ui/src/components/comment-form.tsx29
-rw-r--r--ui/src/components/post-form.tsx28
-rw-r--r--ui/src/components/post-listing.tsx7
-rw-r--r--ui/src/utils.ts5
7 files changed, 90 insertions, 5 deletions
diff --git a/ansible/templates/nginx.conf b/ansible/templates/nginx.conf
index e9fef181..ac4c3526 100644
--- a/ansible/templates/nginx.conf
+++ b/ansible/templates/nginx.conf
@@ -46,6 +46,9 @@ server {
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";
+ # Upload limit for pictshare
+ client_max_body_size 50M;
+
location / {
rewrite (\/(user|u\/|inbox|post|community|c\/|create_post|create_community|login|search|setup|sponsors|communities|modlog|home)+) /static/index.html break;
proxy_pass http://0.0.0.0:8536;
@@ -57,5 +60,12 @@ server {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
+ }
+
+ location /pictshare/ {
+ proxy_pass http://0.0.0.0:8537/;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml
index b7ab8c2b..3f802ab2 100644
--- a/docker/dev/docker-compose.yml
+++ b/docker/dev/docker-compose.yml
@@ -22,5 +22,12 @@ services:
- HOSTNAME=${DOMAIN}
depends_on:
- lemmy_db
+ lemmy_pictshare:
+ image: hascheksolutions/pictshare:latest
+ ports:
+ - "8537:80"
+ volumes:
+ - lemmy_pictshare:/usr/share/nginx/html/data
volumes:
lemmy_db:
+ lemmy_pictshare:
diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml
index a4d9c7b8..74cf1c25 100644
--- a/docker/prod/docker-compose.yml
+++ b/docker/prod/docker-compose.yml
@@ -20,5 +20,12 @@ services:
- HOSTNAME=${DOMAIN}
depends_on:
- lemmy_db
+ lemmy_pictshare:
+ image: hascheksolutions/pictshare:latest
+ ports:
+ - "8537:80"
+ volumes:
+ - lemmy_pictshare:/usr/share/nginx/html/data
volumes:
- lemmy_db:
+ lemmy_db:
+ lemmy_pictshare:
diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx
index e18a6e3f..837cefb5 100644
--- a/ui/src/components/comment-form.tsx
+++ b/ui/src/components/comment-form.tsx
@@ -136,7 +136,10 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
}
{this.props.node && <button type="button" class="btn btn-sm btn-secondary" onClick={linkEvent(this, this.handleReplyCancel)}><T i18nKey="cancel">#</T></button>}
<a href={markdownHelpUrl} target="_blank" class="d-inline-block float-right text-muted small font-weight-bold"><T i18nKey="formatting_help">#</T></a>
- <a href={imageUploadUrl} target="_blank" class="d-inline-block mr-2 float-right text-muted small font-weight-bold"><T i18nKey="upload_image">#</T></a>
+ <form class="d-inline-block mr-2 float-right text-muted small font-weight-bold">
+ <label htmlFor={`file-upload-${this.id}`} class="pointer"><T i18nKey="upload_image">#</T></label>
+ <input id={`file-upload-${this.id}`} type="file" name="file" class="d-none" onChange={linkEvent(this, this.handleImageUpload)} />
+ </form>
</div>
</div>
</form>
@@ -154,8 +157,8 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
i.state.previewMode = false;
i.state.commentForm.content = undefined;
- i.setState(i.state);
event.target.reset();
+ i.setState(i.state);
if (i.props.node) {
i.props.onReplyCancel();
}
@@ -177,6 +180,28 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
handleReplyCancel(i: CommentForm) {
i.props.onReplyCancel();
}
+
+ handleImageUpload(i: CommentForm, event: any) {
+ event.preventDefault();
+ let file = event.target.files[0];
+ const imageUploadUrl = `/pictshare/api/upload.php`;
+ const formData = new FormData();
+ formData.append('file', file);
+ fetch(imageUploadUrl, {
+ method: 'POST',
+ body: formData,
+ })
+ .then(res => res.json())
+ .then(res => {
+ let url = `${window.location.origin}/pictshare/${res.url}`;
+ let markdown = (res.filetype == 'mp4') ? `[vid](${url}/raw)` : `![](${url})`;
+ let content = i.state.commentForm.content;
+ content = (content) ? `${content} ${markdown}` : markdown;
+ i.state.commentForm.content = content;
+ i.setState(i.state);
+ })
+ .catch((error) => alert(error));
+ }
userSearch(text: string, cb: any) {
if (text) {
diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx
index 2e94e177..1591dde0 100644
--- a/ui/src/components/post-form.tsx
+++ b/ui/src/components/post-form.tsx
@@ -109,7 +109,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
{this.state.suggestedTitle &&
<div class="mt-1 text-muted small font-weight-bold pointer" onClick={linkEvent(this, this.copySuggestedTitle)}><T i18nKey="copy_suggested_title" interpolation={{title: this.state.suggestedTitle}}>#</T></div>
}
- <a href={imageUploadUrl} target="_blank" class="d-inline-block mr-2 float-right text-muted small font-weight-bold"><T i18nKey="upload_image">#</T></a>
+ <form>
+ <label htmlFor="file-upload" class="pointer d-inline-block mr-2 float-right text-muted small font-weight-bold"><T i18nKey="upload_image">#</T></label>
+ <input id="file-upload" type="file" name="file" class="d-none" onChange={linkEvent(this, this.handleImageUpload)} />
+ </form>
{this.state.crossPosts.length > 0 &&
<>
<div class="my-1 text-muted small font-weight-bold"><T i18nKey="cross_posts">#</T></div>
@@ -266,6 +269,29 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
i.setState(i.state);
}
+ handleImageUpload(i: PostForm, event: any) {
+ event.preventDefault();
+ let file = event.target.files[0];
+ const imageUploadUrl = `/pictshare/api/upload.php`;
+ const formData = new FormData();
+ formData.append('file', file);
+ fetch(imageUploadUrl, {
+ method: 'POST',
+ body: formData,
+ })
+ .then(res => res.json())
+ .then(res => {
+ let url = `${window.location.origin}/pictshare/${res.url}`;
+ if (res.filetype == 'mp4') {
+ url += '/raw';
+ }
+
+ i.state.postForm.url = url;
+ i.setState(i.state);
+ })
+ .catch((error) => alert(error));
+ }
+
parseMessage(msg: any) {
let op: UserOperation = msgOp(msg);
if (msg.error) {
diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx
index ccd3ce45..5b83c74e 100644
--- a/ui/src/components/post-listing.tsx
+++ b/ui/src/components/post-listing.tsx
@@ -4,7 +4,7 @@ import { WebSocketService, UserService } from '../services';
import { Post, CreatePostLikeForm, PostForm as PostFormI, SavePostForm, CommunityUser, UserView, BanType, BanFromCommunityForm, BanUserForm, AddModToCommunityForm, AddAdminForm, TransferSiteForm, TransferCommunityForm } from '../interfaces';
import { MomentTime } from './moment-time';
import { PostForm } from './post-form';
-import { mdToHtml, canMod, isMod, isImage, getUnixTime } from '../utils';
+import { mdToHtml, canMod, isMod, isImage, isVideo, getUnixTime } from '../utils';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@@ -86,6 +86,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{post.url && isImage(post.url) &&
<span title={i18n.t('expand_here')} class="pointer" onClick={linkEvent(this, this.handleImageExpandClick)}><img class="mx-2 mt-1 float-left img-fluid thumbnail rounded" src={post.url} /></span>
}
+ {post.url && isVideo(post.url) &&
+ <video controls autoPlay muted loop class="mx-2 mt-1 float-left img-fluid thumbnail rounded">
+ <source src={post.url} type="video/mp4" />
+ </video>
+ }
<div className="ml-4">
<div className="post-title">
<h5 className="mb-0 d-inline">
diff --git a/ui/src/utils.ts b/ui/src/utils.ts
index 2d5076a5..4deafd8b 100644
--- a/ui/src/utils.ts
+++ b/ui/src/utils.ts
@@ -104,11 +104,16 @@ export function isMod(modIds: Array<number>, creator_id: number): boolean {
var imageRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:png|jpg|jpeg|gif|png|svg))`);
+var videoRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:mp4))`);
export function isImage(url: string) {
return imageRegex.test(url);
}
+export function isVideo(url: string) {
+ return videoRegex.test(url);
+}
+
export function validURL(str: string) {
var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name