diff options
-rw-r--r-- | ansible/templates/nginx.conf | 10 | ||||
-rw-r--r-- | docker/dev/docker-compose.yml | 7 | ||||
-rw-r--r-- | docker/prod/docker-compose.yml | 9 | ||||
-rw-r--r-- | ui/src/components/comment-form.tsx | 29 | ||||
-rw-r--r-- | ui/src/components/post-form.tsx | 28 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 7 | ||||
-rw-r--r-- | ui/src/utils.ts | 5 |
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 |