Browse Source

feat: allow images/file/video to be uploaded using url

pull/230/head
0oAstro 1 year ago
parent
commit
871b4469f7
Failed to extract signature
  1. 1
      .envrc
  2. 484
      docs/openapi.yaml
  3. 25
      flake.lock
  4. 38
      flake.nix
  5. 6
      readme.md
  6. 1
      src/domains/send/file.go
  7. 1
      src/domains/send/image.go
  8. 1
      src/domains/send/video.go
  9. 40
      src/internal/rest/send.go
  10. 157
      src/services/send.go
  11. 23
      src/validations/send_validation.go
  12. 67
      src/views/components/SendFile.js
  13. 68
      src/views/components/SendImage.js
  14. 69
      src/views/components/SendVideo.js

1
.envrc

@ -0,0 +1 @@
use flake

484
docs/openapi.yaml
File diff suppressed because it is too large
View File

25
flake.lock

@ -0,0 +1,25 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1731676054,
"narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=",
"rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add",
"revCount": 708622,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.708622%2Brev-5e4fbfb6b3de1aa2872b76d49fafc942626e2add/0193363c-ab27-7bbd-af1d-3e6093ed5e2d/source.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://flakehub.com/f/NixOS/nixpkgs/0.1.%2A.tar.gz"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

38
flake.nix

@ -0,0 +1,38 @@
{
description = "A Nix-flake-based Go 1.22 development environment";
inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.*.tar.gz";
outputs = { self, nixpkgs }:
let
goVersion = 22; # Change this to update the whole stack
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
pkgs = import nixpkgs {
inherit system;
overlays = [ self.overlays.default ];
};
});
in
{
overlays.default = final: prev: {
go = final."go_1_${toString goVersion}";
};
devShells = forEachSupportedSystem ({ pkgs }: {
default = pkgs.mkShell {
packages = with pkgs; [
# go (version is specified by overlay)
go
# goimports, godoc, etc.
gotools
# https://github.com/golangci/golangci-lint
golangci-lint
];
};
});
};
}

6
readme.md

@ -37,7 +37,9 @@ Now that we support ARM64 for Linux:
Our webhook will be sent to you with an HMAC header and a sha256 default key `secret`.<br>
You may modify this by using the option below:
- `--webhook-secret="secret"`
- For more command `./main --help`
### Required (without docker)
@ -104,7 +106,7 @@ You can fork or edit this source code !
- Furthermore you can generate HTTP Client from this API using [openapi-generator](https://openapi-generator.tech/#try)
| Feature | Menu | Method | URL |
|---------|------------------------------|--------|-------------------------------|
| ------- | ---------------------------- | ------ | ----------------------------- |
| ✅ | Login with Scan QR | GET | /app/login |
| ✅ | Login With Pair Code | GET | /app/login-with-code |
| ✅ | Logout | GET | /app/logout |
@ -147,7 +149,7 @@ You can fork or edit this source code !
### User Interface
| Description | Image |
|--------------------|------------------------------------------------------------------------------------------|
| ------------------ | ---------------------------------------------------------------------------------------- |
| Homepage | ![Homepage](https://i.ibb.co.com/Sy0dHZp/homepage-v4-20.png) |
| Login | ![Login](https://i.ibb.co.com/jkcB15R/login.png?v=1) |
| Login With Code | ![Login With Code](https://i.ibb.co.com/rdJGvGw/paircode.png) |

1
src/domains/send/file.go

@ -6,4 +6,5 @@ type FileRequest struct {
Phone string `json:"phone" form:"phone"`
File *multipart.FileHeader `json:"file" form:"file"`
Caption string `json:"caption" form:"caption"`
FileUrl string `json:"file_url" form:"file_url"`
}

1
src/domains/send/image.go

@ -6,6 +6,7 @@ type ImageRequest struct {
Phone string `json:"phone" form:"phone"`
Caption string `json:"caption" form:"caption"`
Image *multipart.FileHeader `json:"image" form:"image"`
ImageUrl string `json:"image_url" form:"image_url"`
ViewOnce bool `json:"view_once" form:"view_once"`
Compress bool `json:"compress"`
}

1
src/domains/send/video.go

@ -8,4 +8,5 @@ type VideoRequest struct {
Video *multipart.FileHeader `json:"video" form:"video"`
ViewOnce bool `json:"view_once" form:"view_once"`
Compress bool `json:"compress"`
VideoUrl string `json:"video_url" form:"video_url"`
}

40
src/internal/rest/send.go

@ -5,6 +5,7 @@ import (
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/utils"
"github.com/aldinokemal/go-whatsapp-web-multidevice/pkg/whatsapp"
"github.com/gofiber/fiber/v2"
"github.com/sirupsen/logrus"
)
type Send struct {
@ -50,14 +51,31 @@ func (controller *Send) SendImage(c *fiber.Ctx) error {
err := c.BodyParser(&request)
utils.PanicIfNeeded(err)
file, err := c.FormFile("image")
utils.PanicIfNeeded(err)
// Add debug logging
logrus.WithFields(logrus.Fields{
"body": c.Body(),
"form": c.FormValue("image_url"),
}).Debug("Image request received")
request.ImageUrl = c.FormValue("image_url")
if request.ImageUrl == "" {
if file, err := c.FormFile("image"); err == nil {
request.Image = file
logrus.WithField("filename", file.Filename).Debug("Image file received")
} else {
logrus.WithError(err).Debug("No image file found")
}
} else {
logrus.WithField("url", request.ImageUrl).Debug("Image URL received")
}
whatsapp.SanitizePhone(&request.Phone)
response, err := controller.Service.SendImage(c.UserContext(), request)
utils.PanicIfNeeded(err)
if err != nil {
logrus.WithError(err).Error("Failed to send image")
return err
}
return c.JSON(utils.ResponseData{
Status: 200,
@ -72,10 +90,12 @@ func (controller *Send) SendFile(c *fiber.Ctx) error {
err := c.BodyParser(&request)
utils.PanicIfNeeded(err)
file, err := c.FormFile("file")
utils.PanicIfNeeded(err)
request.FileUrl = c.FormValue("file_url")
if request.FileUrl == "" {
if file, err := c.FormFile("file"); err == nil {
request.File = file
}
}
whatsapp.SanitizePhone(&request.Phone)
response, err := controller.Service.SendFile(c.UserContext(), request)
@ -94,10 +114,12 @@ func (controller *Send) SendVideo(c *fiber.Ctx) error {
err := c.BodyParser(&request)
utils.PanicIfNeeded(err)
video, err := c.FormFile("video")
utils.PanicIfNeeded(err)
request.VideoUrl = c.FormValue("video_url")
if request.VideoUrl == "" {
if video, err := c.FormFile("video"); err == nil {
request.Video = video
}
}
whatsapp.SanitizePhone(&request.Phone)
response, err := controller.Service.SendVideo(c.UserContext(), request)

157
src/services/send.go

@ -3,6 +3,11 @@ package services
import (
"context"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"github.com/aldinokemal/go-whatsapp-web-multidevice/config"
"github.com/aldinokemal/go-whatsapp-web-multidevice/domains/app"
domainSend "github.com/aldinokemal/go-whatsapp-web-multidevice/domains/send"
@ -19,9 +24,6 @@ import (
"go.mau.fi/whatsmeow/proto/waE2E"
"go.mau.fi/whatsmeow/types"
"google.golang.org/protobuf/proto"
"net/http"
"os"
"os/exec"
)
type serviceSend struct {
@ -36,6 +38,23 @@ func NewSendService(waCli *whatsmeow.Client, appService app.IAppService) domainS
}
}
func downloadFileFromURL(url, path string) error {
resp, err := http.Get(url)
if (err != nil) {
return err
}
defer resp.Body.Close()
out, err := os.Create(path)
if (err != nil) {
return err
}
defer out.Close()
_, err = io.Copy(out, resp.Body)
return err
}
func (service serviceSend) SendText(ctx context.Context, request domainSend.MessageRequest) (response domainSend.GenericResponse, err error) {
err = validations.ValidateSendMessage(ctx, request)
if err != nil {
@ -98,53 +117,72 @@ func (service serviceSend) SendText(ctx context.Context, request domainSend.Mess
}
func (service serviceSend) SendImage(ctx context.Context, request domainSend.ImageRequest) (response domainSend.GenericResponse, err error) {
logrus.WithFields(logrus.Fields{
"phone": request.Phone,
"url": request.ImageUrl,
"file": request.Image != nil,
}).Debug("SendImage request received")
err = validations.ValidateSendImage(ctx, request)
if err != nil {
return response, err
}
dataWaRecipient, err := whatsapp.ValidateJidWithLogin(service.WaCli, request.Phone)
if err != nil {
return response, err
}
var (
oriImagePath string
imagePath string
imageThumbnail string
deletedItems []string
filename string
)
// Save image to server
oriImagePath := fmt.Sprintf("%s/%s", config.PathSendItems, request.Image.Filename)
// Generate unique filename
filename = fmt.Sprintf("image-%s%s", fiberUtils.UUIDv4(), ".jpg")
oriImagePath = fmt.Sprintf("%s/%s", config.PathSendItems, filename)
// Handle image from URL or file
if request.ImageUrl != "" {
logrus.WithField("url", request.ImageUrl).Debug("Downloading image from URL")
err = downloadFileFromURL(request.ImageUrl, oriImagePath)
if err != nil {
return response, fmt.Errorf("failed to download image: %v", err)
}
deletedItems = append(deletedItems, oriImagePath)
} else if request.Image != nil {
logrus.WithField("filename", request.Image.Filename).Debug("Saving uploaded image")
err = fasthttp.SaveMultipartFile(request.Image, oriImagePath)
if err != nil {
return response, err
return response, fmt.Errorf("failed to save image: %v", err)
}
deletedItems = append(deletedItems, oriImagePath)
} else {
return response, pkgError.ValidationError("either ImageUrl or Image must be provided")
}
/* Generate thumbnail with smalled image size */
// Generate thumbnail
imageThumbnail = fmt.Sprintf("%s/thumb-%s", config.PathSendItems, filename)
srcImage, err := imaging.Open(oriImagePath)
if err != nil {
return response, pkgError.InternalServerError(fmt.Sprintf("failed to open image %v", err))
}
// Resize Thumbnail
resizedImage := imaging.Resize(srcImage, 100, 0, imaging.Lanczos)
imageThumbnail = fmt.Sprintf("%s/thumbnails-%s", config.PathSendItems, request.Image.Filename)
if err = imaging.Save(resizedImage, imageThumbnail); err != nil {
return response, pkgError.InternalServerError(fmt.Sprintf("failed to save thumbnail %v", err))
}
deletedItems = append(deletedItems, imageThumbnail)
// Handle compression if needed
if request.Compress {
// Resize image
openImageBuffer, err := imaging.Open(oriImagePath)
if err != nil {
return response, pkgError.InternalServerError(fmt.Sprintf("failed to open image %v", err))
}
newImage := imaging.Resize(openImageBuffer, 600, 0, imaging.Lanczos)
newImagePath := fmt.Sprintf("%s/new-%s", config.PathSendItems, request.Image.Filename)
logrus.Debug("Compressing image")
newImagePath := fmt.Sprintf("%s/compressed-%s", config.PathSendItems, filename)
newImage := imaging.Resize(srcImage, 600, 0, imaging.Lanczos)
if err = imaging.Save(newImage, newImagePath); err != nil {
return response, pkgError.InternalServerError(fmt.Sprintf("failed to save image %v", err))
return response, pkgError.InternalServerError(fmt.Sprintf("failed to save compressed image %v", err))
}
deletedItems = append(deletedItems, newImagePath)
imagePath = newImagePath
@ -152,25 +190,26 @@ func (service serviceSend) SendImage(ctx context.Context, request domainSend.Ima
imagePath = oriImagePath
}
// Send to WA server
dataWaCaption := request.Caption
// Send to WhatsApp
logrus.Debug("Uploading to WhatsApp")
dataWaImage, err := os.ReadFile(imagePath)
if err != nil {
return response, err
}
uploadedImage, err := service.uploadMedia(ctx, whatsmeow.MediaImage, dataWaImage, dataWaRecipient)
if err != nil {
fmt.Printf("failed to upload file: %v", err)
return response, err
return response, fmt.Errorf("failed to upload image: %v", err)
}
dataWaThumbnail, err := os.ReadFile(imageThumbnail)
if err != nil {
return response, pkgError.InternalServerError(fmt.Sprintf("failed to read thumbnail %v", err))
}
// Prepare and send message
msg := &waE2E.Message{ImageMessage: &waE2E.ImageMessage{
JPEGThumbnail: dataWaThumbnail,
Caption: proto.String(dataWaCaption),
Caption: proto.String(request.Caption),
URL: proto.String(uploadedImage.URL),
DirectPath: proto.String(uploadedImage.DirectPath),
MediaKey: uploadedImage.MediaKey,
@ -180,19 +219,21 @@ func (service serviceSend) SendImage(ctx context.Context, request domainSend.Ima
FileLength: proto.Uint64(uint64(len(dataWaImage))),
ViewOnce: proto.Bool(request.ViewOnce),
}}
ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msg)
go func() {
errDelete := utils.RemoveFile(0, deletedItems...)
if errDelete != nil {
fmt.Println("error when deleting picture: ", errDelete)
}
}()
if err != nil {
return response, err
}
// Cleanup files
go func() {
if err := utils.RemoveFile(0, deletedItems...); err != nil {
logrus.WithError(err).Error("Failed to cleanup files")
}
}()
response.MessageID = ts.ID
response.Status = fmt.Sprintf("Message sent to %s (server timestamp: %s)", request.Phone, ts.Timestamp.String())
response.Status = fmt.Sprintf("Image sent to %s (server timestamp: %s)", request.Phone, ts.Timestamp)
return response, nil
}
@ -206,6 +247,44 @@ func (service serviceSend) SendFile(ctx context.Context, request domainSend.File
return response, err
}
if request.FileUrl != "" {
fileBytes, err := http.Get(request.FileUrl)
if err != nil {
return response, err
}
defer fileBytes.Body.Close()
data, err := io.ReadAll(fileBytes.Body)
if err != nil {
return response, err
}
fileMimeType := http.DetectContentType(data)
uploadedFile, err := service.uploadMedia(ctx, whatsmeow.MediaDocument, data, dataWaRecipient)
if err != nil {
fmt.Printf("Failed to upload file: %v", err)
return response, err
}
msg := &waE2E.Message{DocumentMessage: &waE2E.DocumentMessage{
URL: proto.String(uploadedFile.URL),
Mimetype: proto.String(fileMimeType),
Title: proto.String(request.File.Filename),
FileSHA256: uploadedFile.FileSHA256,
FileLength: proto.Uint64(uploadedFile.FileLength),
MediaKey: uploadedFile.MediaKey,
FileName: proto.String(request.File.Filename),
FileEncSHA256: uploadedFile.FileEncSHA256,
DirectPath: proto.String(uploadedFile.DirectPath),
Caption: proto.String(request.Caption),
}}
ts, err := service.WaCli.SendMessage(ctx, dataWaRecipient, msg)
if err != nil {
return response, err
}
response.MessageID = ts.ID
response.Status = fmt.Sprintf("Document sent to %s (server timestamp: %s)", request.Phone, ts.Timestamp.String())
return response, nil
} else if request.File != nil {
fileBytes := helpers.MultipartFormFileHeaderToBytes(request.File)
fileMimeType := http.DetectContentType(fileBytes)
@ -236,6 +315,9 @@ func (service serviceSend) SendFile(ctx context.Context, request domainSend.File
response.MessageID = ts.ID
response.Status = fmt.Sprintf("Document sent to %s (server timestamp: %s)", request.Phone, ts.Timestamp.String())
return response, nil
} else {
return response, pkgError.ValidationError("either FileUrl or File must be provided")
}
}
func (service serviceSend) SendVideo(ctx context.Context, request domainSend.VideoRequest) (response domainSend.GenericResponse, err error) {
@ -249,6 +331,7 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
}
var (
oriVideoPath string
videoPath string
videoThumbnail string
deletedItems []string
@ -256,11 +339,21 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
generateUUID := fiberUtils.UUIDv4()
// Save video to server
oriVideoPath := fmt.Sprintf("%s/%s", config.PathSendItems, generateUUID+request.Video.Filename)
if request.VideoUrl != "" {
oriVideoPath = fmt.Sprintf("%s/url-video-%s.mp4", config.PathSendItems, generateUUID)
err = downloadFileFromURL(request.VideoUrl, oriVideoPath)
if err != nil {
return response, err
}
} else if request.Video != nil {
oriVideoPath = fmt.Sprintf("%s/%s", config.PathSendItems, generateUUID+request.Video.Filename)
err = fasthttp.SaveMultipartFile(request.Video, oriVideoPath)
if err != nil {
return response, pkgError.InternalServerError(fmt.Sprintf("failed to store video in server %v", err))
}
} else {
return response, pkgError.ValidationError("either VideoUrl or Video must be provided")
}
// Check if ffmpeg is installed
_, err = exec.LookPath("ffmpeg")
@ -296,7 +389,7 @@ func (service serviceSend) SendVideo(ctx context.Context, request domainSend.Vid
cmdCompress := exec.Command("ffmpeg", "-i", oriVideoPath, "-strict", "-2", compresVideoPath)
err = cmdCompress.Run()
if err != nil {
if (err != nil) {
return response, pkgError.InternalServerError("failed to compress video")
}

23
src/validations/send_validation.go

@ -26,69 +26,68 @@ func ValidateSendMessage(ctx context.Context, request domainSend.MessageRequest)
func ValidateSendImage(ctx context.Context, request domainSend.ImageRequest) error {
err := validation.ValidateStructWithContext(ctx, &request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.Image, validation.Required),
)
if err != nil {
return pkgError.ValidationError(err.Error())
}
// Skip mime validation for URL
if request.ImageUrl != "" {
return nil
}
if request.Image != nil {
availableMimes := map[string]bool{
"image/jpeg": true,
"image/jpg": true,
"image/png": true,
}
if !availableMimes[request.Image.Header.Get("Content-Type")] {
return pkgError.ValidationError("your image is not allowed. please use jpg/jpeg/png")
}
}
return nil
}
func ValidateSendFile(ctx context.Context, request domainSend.FileRequest) error {
err := validation.ValidateStructWithContext(ctx, &request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.File, validation.Required),
)
if err != nil {
return pkgError.ValidationError(err.Error())
}
if request.File != nil {
if request.File.Size > config.WhatsappSettingMaxFileSize { // 10MB
maxSizeString := humanize.Bytes(uint64(config.WhatsappSettingMaxFileSize))
return pkgError.ValidationError(fmt.Sprintf("max file upload is %s, please upload in cloud and send via text if your file is higher than %s", maxSizeString, maxSizeString))
}
}
return nil
}
func ValidateSendVideo(ctx context.Context, request domainSend.VideoRequest) error {
err := validation.ValidateStructWithContext(ctx, &request,
validation.Field(&request.Phone, validation.Required),
validation.Field(&request.Video, validation.Required),
)
if err != nil {
return pkgError.ValidationError(err.Error())
}
if request.Video != nil {
availableMimes := map[string]bool{
"video/mp4": true,
"video/x-matroska": true,
"video/avi": true,
}
if !availableMimes[request.Video.Header.Get("Content-Type")] {
return pkgError.ValidationError("your video type is not allowed. please use mp4/mkv/avi")
}
if request.Video.Size > config.WhatsappSettingMaxVideoSize { // 30MB
maxSizeString := humanize.Bytes(uint64(config.WhatsappSettingMaxVideoSize))
return pkgError.ValidationError(fmt.Sprintf("max video upload is %s, please upload in cloud and send via text if your file is higher than %s", maxSizeString, maxSizeString))
}
}
return nil
}

67
src/views/components/SendFile.js

@ -1,54 +1,66 @@
import FormRecipient from "./generic/FormRecipient.js";
export default {
name: 'SendFile',
name: "SendFile",
components: {
FormRecipient
FormRecipient,
},
props: {
maxFileSize: {
type: String,
required: true,
}
},
},
data() {
return {
caption: '',
caption: "",
type: window.TYPEUSER,
phone: '',
phone: "",
loading: false,
}
file_url: "",
};
},
computed: {
phone_id() {
return this.phone + this.type;
}
},
},
methods: {
openModal() {
$('#modalSendFile').modal({
$("#modalSendFile")
.modal({
onApprove: function () {
return false;
}
}).modal('show');
},
})
.modal("show");
},
async handleSubmit() {
try {
let response = await this.submitApi()
showSuccessInfo(response)
$('#modalSendFile').modal('hide');
if (!this.file_url && !$("#file_input")[0].files[0]) {
throw new Error("Please provide either a file URL or upload a file.");
}
let response = await this.submitApi();
showSuccessInfo(response);
$("#modalSendFile").modal("hide");
} catch (err) {
showErrorInfo(err)
showErrorInfo(err);
}
},
async submitApi() {
this.loading = true;
try {
let payload = new FormData();
payload.append("caption", this.caption)
payload.append("phone", this.phone_id)
payload.append("file", $("#file_file")[0].files[0])
let response = await window.http.post(`/send/file`, payload)
payload.append("caption", this.caption);
payload.append("phone", this.phone_id);
if (this.file_url) {
payload.append("file_url", this.file_url);
} else {
payload.append("file", $("#file_input")[0].files[0]);
}
let response = await window.http.post(`/send/file`, payload);
this.handleReset();
return response.data.message;
} catch (error) {
@ -61,10 +73,11 @@ export default {
}
},
handleReset() {
this.caption = '';
this.phone = '';
this.caption = "";
this.phone = "";
this.type = window.TYPEUSER;
$("#file_file").val('');
this.file_url = "";
$("#file_input").val("");
},
},
template: `
@ -94,10 +107,14 @@ export default {
<textarea v-model="caption" placeholder="Type some caption (optional)..."
aria-label="caption"></textarea>
</div>
<div class="field">
<label>File URL</label>
<input v-model="file_url" type="text" placeholder="http://example.com/file.pdf" aria-label="file url">
</div>
<div class="field" style="padding-bottom: 30px">
<label>File</label>
<input type="file" style="display: none" id="file_file">
<label for="file_file" class="ui positive medium green left floated button" style="color: white">
<input type="file" style="display: none" id="file_input" accept="*/*"/>
<label for="file_input" class="ui positive medium green left floated button" style="color: white">
<i class="ui upload icon"></i>
Upload file
</label>
@ -112,5 +129,5 @@ export default {
</div>
</div>
</div>
`
}
`,
};

68
src/views/components/SendImage.js

@ -1,54 +1,67 @@
import FormRecipient from "./generic/FormRecipient.js";
export default {
name: 'SendImage',
name: "SendImage",
components: {
FormRecipient
FormRecipient,
},
data() {
return {
phone: '',
phone: "",
view_once: false,
compress: false,
caption: '',
caption: "",
type: window.TYPEUSER,
loading: false,
selected_file: null
}
selected_file: null,
image_url: "",
};
},
computed: {
phone_id() {
return this.phone + this.type;
}
},
},
methods: {
openModal() {
$('#modalSendImage').modal({
$("#modalSendImage")
.modal({
onApprove: function () {
return false;
}
}).modal('show');
},
})
.modal("show");
},
async handleSubmit() {
try {
let response = await this.submitApi()
showSuccessInfo(response)
$('#modalSendImage').modal('hide');
if (!this.image_url && !$("#file_image")[0].files[0]) {
throw new Error(
"Please provide either an image URL or upload an image file."
);
}
let response = await this.submitApi();
showSuccessInfo(response);
$("#modalSendImage").modal("hide");
} catch (err) {
showErrorInfo(err)
showErrorInfo(err);
}
},
async submitApi() {
this.loading = true;
try {
let payload = new FormData();
payload.append("phone", this.phone_id)
payload.append("view_once", this.view_once)
payload.append("compress", this.compress)
payload.append("caption", this.caption)
payload.append('image', $("#file_image")[0].files[0])
payload.append("phone", this.phone_id);
payload.append("view_once", this.view_once);
payload.append("compress", this.compress);
payload.append("caption", this.caption);
if (this.image_url) {
payload.append("image_url", this.image_url);
} else {
payload.append("image", $("#file_image")[0].files[0]);
}
let response = await window.http.post(`/send/image`, payload)
let response = await window.http.post(`/send/image`, payload);
this.handleReset();
return response.data.message;
} catch (error) {
@ -63,10 +76,11 @@ export default {
handleReset() {
this.view_once = false;
this.compress = false;
this.phone = '';
this.caption = '';
this.phone = "";
this.caption = "";
this.type = window.TYPEUSER;
$("#file_image").val('');
this.image_url = "";
$("#file_image").val("");
},
},
template: `
@ -111,6 +125,10 @@ export default {
<label>Check for compressing image to smaller size</label>
</div>
</div>
<div class="field">
<label>Image URL</label>
<input v-model="image_url" type="text" placeholder="http://example.com/image.jpg" aria-label="image url">
</div>
<div class="field" style="padding-bottom: 30px">
<label>Image</label>
<input type="file" style="display: none" id="file_image" accept="image/png,image/jpg,image/jpeg"/>
@ -129,5 +147,5 @@ export default {
</div>
</div>
</div>
`
}
`,
};

69
src/views/components/SendVideo.js

@ -1,59 +1,73 @@
import FormRecipient from "./generic/FormRecipient.js";
export default {
name: 'SendVideo',
name: "SendVideo",
components: {
FormRecipient
FormRecipient,
},
// define props
props: {
maxVideoSize: {
type: String,
required: true,
}
},
},
data() {
return {
caption: '',
caption: "",
view_once: false,
compress: false,
type: window.TYPEUSER,
phone: '',
phone: "",
loading: false,
}
video_url: "",
};
},
computed: {
phone_id() {
return this.phone + this.type;
}
},
},
methods: {
openModal() {
$('#modalSendVideo').modal({
$("#modalSendVideo")
.modal({
onApprove: function () {
return false;
}
}).modal('show');
},
})
.modal("show");
},
async handleSubmit() {
try {
let response = await this.submitApi()
showSuccessInfo(response)
$('#modalSendVideo').modal('hide');
if (!this.video_url && !$("#file_video")[0].files[0]) {
throw new Error(
"Please provide either a video URL or upload a video file."
);
}
let response = await this.submitApi();
showSuccessInfo(response);
$("#modalSendVideo").modal("hide");
} catch (err) {
showErrorInfo(err)
showErrorInfo(err);
}
},
async submitApi() {
this.loading = true;
try {
let payload = new FormData();
payload.append("phone", this.phone_id)
payload.append("caption", this.caption)
payload.append("view_once", this.view_once)
payload.append("compress", this.compress)
payload.append('video', $("#file_video")[0].files[0])
let response = await window.http.post(`/send/video`, payload)
payload.append("phone", this.phone_id);
payload.append("caption", this.caption);
payload.append("view_once", this.view_once);
payload.append("compress", this.compress);
if (this.video_url) {
payload.append("video_url", this.video_url);
} else {
payload.append("video", $("#file_video")[0].files[0]);
}
let response = await window.http.post(`/send/video`, payload);
this.handleReset();
return response.data.message;
} catch (error) {
@ -66,12 +80,13 @@ export default {
}
},
handleReset() {
this.caption = '';
this.caption = "";
this.view_once = false;
this.compress = false;
this.phone = '';
this.phone = "";
this.type = window.TYPEUSER;
$("#file_video").val('');
this.video_url = "";
$("#file_video").val("");
},
},
template: `
@ -117,6 +132,10 @@ export default {
<label>Check for compressing video to smaller size</label>
</div>
</div>
<div class="field">
<label>Video URL</label>
<input v-model="video_url" type="text" placeholder="http://example.com/video.mp4" aria-label="video url">
</div>
<div class="field" style="padding-bottom: 30px">
<label>Video</label>
<input type="file" style="display: none" accept="video/*" id="file_video">
@ -135,5 +154,5 @@ export default {
</div>
</div>
</div>
`
}
`,
};
Loading…
Cancel
Save