Git Product home page Git Product logo

worxid / worx Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 2.0 3.19 MB

Worx allows your teams to complete forms and collect data anywhere, anytime. Quickly retrieve accurate data, flag critical issues, reduce data entry errors, validate answers, add conditional logic, and more.

Home Page: https://worx.id

License: MIT License

HTML 10.19% JavaScript 86.09% CSS 3.72%
collaboration form form-builder java javascript low-code mobile-data-processing mobile-form reactjs spring-boot

worx's People

Contributors

jaballogian avatar shygnome avatar wabiwabo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

worx's Issues

Add `from` and `to` parameter to search API

Description

Add from and to parameters to enable the filter function in the search API.

To-do list

  • Form Template Search API. The "from" and "to" parameters will be compared to the created date field.
  • Submission Search API. The "from" and "to" parameters will be compared to the submitted date field.
  • Disable the date filter.

Convert this template as html file, read from resources/templates

Description

Convert this template class as an HTML file to read from resources/templates.

Convert to HTML file

package id.worx.worx.web.mailTemplate;
public class EmailVerification {
public static String EmailVerify(String linkUrl, String fullname){
return "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n" +
"\n" +
" <head>\n" +
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" +
" <title>Email Verification</title>\n" +
" <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n" +
" <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n" +
" <link href=\"https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap\" rel=\"stylesheet\">\n" +
" <link href=\"https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap\" rel=\"stylesheet\">\n" +
" </head>\n" +
" \n" +
" <body yahoo=\"\" bgcolor=\"#f8f9fa\" style=\"margin: 0; padding: 0; min-width: 100% !important\">\n" +
" <table width=\"100%\" bgcolor=\"#f8f9fa\" cellpadding=\"0\" cellspacing=\"0\">\n" +
" <tr>\n" +
" <td>\n" +
" <table class=\"content\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"width: 100%; max-width: 541.31px; border: 2px solid rgba(0, 0, 0, 0.87);\">\n" +
" <tr>\n" +
" <td bgcolor=\"#ffffff\" class=\"header\" style=\"padding: 48px 30px 0 30px\">\n" +
" <table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n" +
" <tr>\n" +
" <td style=\"padding: 0 0 0 0\">\n" +
" <img src=\"https://i.ibb.co/j4vm3Z1/worx.png\" alt=\"worx-logo\" border=\"0\" height=\"40\" class=\"fix\" width=\"100%\">" +
" <h1 style=\"\n" +
" font-family: 'Open Sans', sans-serif;\n" +
" font-weight: 600;\n" +
" font-size: 16px;\n" +
" line-height: 22px;\n" +
" text-align: center;\n" +
" \">Welcome to Worx</h1>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td bgcolor=\"#ffffff\" class=\"innerpadding borderbottom\" style=\"padding: 24px 52px 64px 52px;\">\n" +
" <table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n" +
" <tr>\n" +
" <td class=\"bodycopy\" style=\"\n" +
" color: #000000;\n" +
" font-family: 'Open Sans', sans-serif;\n" +
" font-size: 12px;\n" +
" line-height: 16.34px;\n" +
" \">\n" +
" <p>Hi, "+fullname+"!</p>\n" +
" <p style=\"margin-top: 18px;\">\n" +
" Thank you for registering in our application! Worx is a new and easy way to monitor fleet that you have.\n" +
" </p>\n" +
" <p style=\"margin-top: 18px;\">\n" +
" To login your account, please click the button below:\n" +
" </p>\n" +
" <table align=\"center\" class=\"buttonwrapper\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\n" +
" style=\"margin-top: 30px\">\n" +
" <tr>\n" +
" <td class=\"button\" width=\"181\" height=\"36\" bgcolor=\"#DA3630\" style=\" \n" +
" text-align: center;\n" +
" border: 2px solid rgba(0, 0, 0, 0.87);\n" +
" box-shadow: 2px 2px 0px #000000;\n" +
" \">\n" +
" <a href=\""+linkUrl+"\" target=\"_blank\" style=\"\n" +
" font-family: 'Space Mono', sans-serif;\n" +
" font-style: normal;\n" +
" font-weight: 700;\n" +
" font-size: 14px;\n" +
" line-height: 24px;\n" +
" color: #ffffff;\n" +
" letter-spacing: 0.4px;\n" +
" text-decoration: none;\n" +
" \">Confirm Account</a>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" <p style=\"padding: 20px 0 0 0\">\n" +
" By clicking on the button above you will be logged in to your new account at \n" +
" Worx and have to complete access to all features. You also agree to receive \n" +
" occasional emails with helpful hints, product updates, and industry news.\n" +
" </p>\n" +
" <p style=\"margin-top: 18px;\">\n" +
" Thank you<br />\n" +
" Everyone at Worx\n" +
" </p>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td style=\"padding: 12px\" align=\"center\" bgcolor=\"#ffffff\">\n" +
" <p style=\"margin: 0; font-family: 'Open Sans', sans-serif; font-size: 12px;\">®worx 2021</p>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </body>\n" +
" \n" +
" </html>";
}
}

package id.worx.worx.web.mailTemplate;
public class ResetPasswordMail {
public static String ResetPasswordTemplate(String linkUrl, String fullname){
return "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n" +
"\n" +
" <head>\n" +
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" +
" <title>Email Reset Password</title>\n" +
" <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n" +
" <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n" +
" <link href=\"https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap\" rel=\"stylesheet\">\n" +
" <link href=\"https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap\" rel=\"stylesheet\">\n" +
" </head>\n" +
" \n" +
" <body yahoo=\"\" bgcolor=\"#f8f9fa\" style=\"margin: 0; padding: 0; min-width: 100% !important\">\n" +
" <table width=\"100%\" bgcolor=\"#f8f9fa\" cellpadding=\"0\" cellspacing=\"0\">\n" +
" <tr>\n" +
" <td style=\"background-color: #ffffff;\">\n" +
" <table class=\"content\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"width: 100%; max-width: 541.31px; border: 2px solid rgba(0, 0, 0, 0.87);\">\n" +
" <tr>\n" +
" <td bgcolor=\"#ffffff\" class=\"header\" style=\"padding: 64px 30px 56px 30px\">\n" +
" <table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n" +
" <tr>\n" +
" <td style=\"padding: 0 0 0 0\">\n" +
" <img src=\"https://i.ibb.co/j4vm3Z1/worx.png\" alt=\"worx-logo\" border=\"0\" height=\"40\" class=\"fix\" width=\"100%\">" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td bgcolor=\"#ffffff\" class=\"innerpadding borderbottom\" style=\"padding: 0 64px 64px 64px;\">\n" +
" <table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n" +
" <tr>\n" +
" <td class=\"bodycopy\" style=\"\n" +
" color: #000000;\n" +
" font-family: 'Open Sans', sans-serif;\n" +
" font-size: 12px;\n" +
" line-height: 16.34px;\n" +
" \">\n" +
" <p>Hi, "+fullname+"!</p>\n" +
" <p style=\"margin-top: 18px;\">\n" +
" Thank you for using Worx.\n" +
" </br>\n" +
" Please click the following link to change your password:\n" +
" </p>\n" +
" <table align=\"center\" class=\"buttonwrapper\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"\n" +
" style=\"margin-top: 30px\">\n" +
" <tr>\n" +
" <td class=\"button\" width=\"181\" height=\"36\" bgcolor=\"#DA3630\" style=\" \n" +
" text-align: center;\n" +
" border: 2px solid rgba(0, 0, 0, 0.87);\n" +
" box-shadow: 2px 2px 0px #000000;\n" +
" \">\n" +
" <a href=\""+linkUrl+"\" target=\"_blank\" style=\"\n" +
" font-family: 'Space Mono', sans-serif;\n" +
" font-style: normal;\n" +
" font-weight: 700;\n" +
" font-size: 14px;\n" +
" line-height: 24px;\n" +
" color: #ffffff;\n" +
" letter-spacing: 0.4px;\n" +
" text-decoration: none;\n" +
" \">Reset Password</a>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" <p style=\"margin-top: 28px;\">We would be very happy to assist you.</p>\n" +
" <p style=\"margin-top: 18px;\">\n" +
" Thank you<br />\n" +
" Everyone at Worx\n" +
" </p>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td style=\"padding: 12px\" align=\"center\">\n" +
" <p style=\"margin: 0; font-family: 'Open Sans', sans-serif; font-size: 12px;\">®worx 2021</p>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </body>\n" +
" \n" +
" </html>";
}
}

Please also implement this form share template

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Share Link</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
</head>
<body yahoo="" bgcolor="#f8f9fa" style="margin: 0; padding: 0; min-width: 100% !important; font-family: 'Space Mono', sans-serif;">
<table width="100%" bgcolor="#f8f9fa" cellpadding="0" cellspacing="0">
<tr>
<td style="padding: 8px;">
<table class="content" align="center" cellpadding="0" cellspacing="0" border="0" style="width: 100%; max-width: 1024px; border: 2px solid rgba(0, 0, 0, 0.87);">
<tr>
<td bgcolor="#DA3630" class="header" style="padding: 20px 40px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" style="font-size: 12px;">
<img class="fix" src="https://api.dev.worx.id/logo.svg" width="88" alt="worx-logo" />
</table>
</td>
</tr>
<tr>
<td style="padding: 24px 24px 40px 24px;">
<table class="content" align="center" cellpadding="0" cellspacing="0" border="0" style="padding: 40px 24px; width: 100%; max-width: 672px; border: 2px solid rgba(0, 0, 0, 0.87); background-color: #DA36301A;">
<tr>
<td>
<p style="font-size: 14px; margin: 0 0 24px 0;letter-spacing: 1px;">
I’ve invited you to fill in a form:
</p>
<p style="font-size: 18px; font-weight: 500; margin: 0 0 4px 0;">
Valid Form
</p>
<p style="font-size: 12px; margin: 0; color: rgba(0, 0, 0, 0.54);">
Ini adalah deskripsi
</p>
</td>
<td>
<table align="center" class="buttonwrapper" border="0" cellspacing="0" cellpadding="0" style="margin: 44px 0 0 auto;">
<tr>
<td class="button" width="148" height="40" bgcolor="#DA3630" style="text-align: center; border: 2px solid rgba(0, 0, 0, 0.87);">
<a href="http://worx.id/fill-forms?code=" target="_blank" style="
font-family: 'Space Mono', sans-serif;
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 1;
color: #ffffff;
letter-spacing: 0.4px;
text-decoration: none;
">Fill Out Form</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table class="content" align="center" cellpadding="0" cellspacing="0" border="0" style="padding: 0 0 24px 0; width: 100%; max-width: 672px;">
<tr>
<td>
<p style="font-size: 14px; margin: 0;">
Creat your own Form, <a href="http://worx.id/sign-up" style="color: #DA3630; font-weight: 500; text-decoration: none;">Get Started!</a>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

Related Issue(s)

Reference

Blocker

Duplicate implementation with EmailService.java

Description

Duplicate implementation with EmailService.java. Please remove one and refactor the entire class.

package id.worx.worx.service;
import java.nio.charset.StandardCharsets;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import id.worx.worx.common.model.dto.EmailDTO;
import id.worx.worx.config.properties.WorxProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Service
@Slf4j
@RequiredArgsConstructor
public class EmailServiceImpl implements EmailService {
private final WorxProperties worxProps;
private static final String EMAIL_RESET_PASSWORD_TEMPLATE = "email-reset-password.html";
private final JavaMailSender javaMailSender;
private final TemplateEngine templateEngine;
@Override
public void sendEmail(EmailDTO email) {
MimeMessage message = javaMailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(
message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
helper.setTo(email.getTo());
helper.setText(email.getContent(), true);
helper.setSubject(email.getSubject());
helper.setFrom(email.getFrom());
javaMailSender.send(message);
log.info("Mail sent to : " + email.getTo());
} catch (MessagingException e) {
log.error("Mail Sending failure : " + e.getMessage(), e);
}
}
@Override
public void sendRestorePasswordEmail(String email, String content) {
Context context = new Context();
context.setVariable("confirmationUrl", content);
context.setVariable("greeting", String.format("Hi %s,", email));
String body = templateEngine.process(EMAIL_RESET_PASSWORD_TEMPLATE, context);
EmailDTO emailDTO = EmailDTO.builder()
.from(worxProps.getMail().getFromAddress())
.to(email)
.content(body)
.subject("Restore Password for Your Lacak Account")
.build();
sendEmail(emailDTO);
}
@Override
public void sendShareFormEmail(String email, String code) {
String url = String.format("https://dev.worx.id/fill-form?code=%s", code);
log.info("share url {}", url);
EmailDTO emailDTO = EmailDTO.builder()
.from(worxProps.getMail().getFromAddress())
.to(email)
.content(url)
.subject("Fill Your Form with Worx")
.build();
sendEmail(emailDTO);
}
}

package id.worx.worx.service;
import id.worx.worx.config.properties.WorxProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.thymeleaf.spring5.SpringTemplateEngine;
import javax.mail.internet.MimeMessage;
import java.nio.charset.StandardCharsets;
@Service
@Slf4j
public class MailService {
private static final String USER = "user";
private static final String BASE_URL = "baseUrl";
private final WorxProperties worxProperties;
private final JavaMailSender javaMailSender;
private final MessageSource messageSource;
private final SpringTemplateEngine templateEngine;
public MailService(WorxProperties worxProperties, JavaMailSender javaMailSender,
MessageSource messageSource, SpringTemplateEngine templateEngine) {
this.worxProperties = worxProperties;
this.javaMailSender = javaMailSender;
this.messageSource = messageSource;
this.templateEngine = templateEngine;
}
@Async
public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
isMultipart, isHtml, to, subject, content);
// Prepare message using a Spring helper
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name());
message.setTo(to);
message.setFrom(worxProperties.getMail().getFromAddress());
message.setSubject(subject);
message.setText(content, isHtml);
javaMailSender.send(mimeMessage);
log.debug("Sent email to User '{}'", to);
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.warn("Email could not be sent to user '{}'", to, e);
} else {
log.warn("Email could not be sent to user '{}': {}", to, e.getMessage());
}
}
}
@Async
public void sendEmailTemplate(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
log.debug("Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
isMultipart, isHtml, to, subject, content);
// Prepare message using a Spring helper
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name());
message.setTo(to);
message.setFrom(worxProperties.getMail().getFromAddress());
message.setSubject(subject);
message.setText(content, isHtml);
javaMailSender.send(mimeMessage);
log.debug("Sent email to User '{}'", to);
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.warn("Email could not be sent to user '{}'", to, e);
} else {
log.warn("Email could not be sent to user '{}': {}", to, e.getMessage());
}
}
}
}

Related Issue(s)

Reference

Blocker

Guest API

Description

Separate all APIs for guest users, including the file and share API.

Form Submission Search API - Filter by Source parameter

Description

Update Form Submission Search API request body to provide filter feature by source parameter.

Current Request Body

{
  "label": "string",
  "description": "string",
  "createdOn": "2022-11-21T02:27:06.089Z",
  "modifiedOn": "2022-11-21T02:27:06.089Z",
  "submitDate": "2022-11-21T02:27:06.089Z",
  "from": "2022-11-21T02:27:06.089Z",
  "to": "2022-11-21T02:27:06.089Z",
  "template_id": 0,
  "submit_address": "string",
  "respondent_label": "string",
  "global_search": "string"
}

Expected Request Body

{
  "label": "string",
  "description": "string",
  "from": "2022-11-21T02:27:06.089Z",
  "to": "2022-11-21T02:27:06.089Z",
  "template_id": 0,
  "submit_address": "string",
  "source": {
      "type": "MOBILE_APP",
      "label": "string"
  },
  "global_search": "string"
}
  • Omit unused date fields (created_on, modified_on, and submit_date).
  • Global search also takes effect on source_type and source_label fields.

Messaging

Description

Implement messaging technology to provide notification features and realtime updates.

Remove the `@NotEmpty` annotation

Description

Remove the @NotEmpty annotation on the fields field to accommodate empty form creation.

@NotBlank
private String label;
private String description;
@NotEmpty
private List<Field> fields;
@JsonProperty("submit_in_zone")
private Boolean submitInZone;
@JsonProperty("default")
private Boolean isDefaultForm;

Expectation

The API should accept this request body example.

{
  "label": "My New Empty Form",
  "description": "New Form with empty fields",
  "fields": [ ],
  "submit_in_zone": true,
  "default": false
}

Get File API

Description

Create GET API for a single file or multiple files. It returns a File response, including the URL (presigned URL) and the File stats.

Specification

  • Web, Authenticated by Token
    GET /media/files

Request body

{
    "file_ids": [ 1, 2, 3]
}

Response, UrlPresignedResponse

{
    "status": true
    "list": [
        {
            "
        }
    ]
}
  • Mobile

Related File(s)

  • FileStorageService
    package id.worx.worx.service.storage;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import id.worx.worx.common.model.response.UrlPresignedResponse;
    public interface FileStorageService {
    void store();
    UrlPresignedResponse getUploadUrl(String filename);
    UrlPresignedResponse getUploadUrl(Long fileId);
    UrlPresignedResponse getDownloadUrl(Long fileId);
    boolean isObjectExist(String path);
    long getObjectSize(String path);
    default String generateUniquePath(String filename, String foldername) {
    DateFormat writeFormat = new SimpleDateFormat("yyyy/MM/dd/HH/mm/ss");
    return String.format("%s/%s/%s", foldername.toLowerCase(), writeFormat.format(new Date()), filename);
    }
    }

Frontend - Documentation

This issue is just documentation.

Deployed app: https://dev.worx.id/sign-in

List of licenses:

JSON object form:

Component Design: https://whimsical.com/sketch-3aN9P3fud7mpb1hWt4A4w3

{
  label: 'Eksplor - 2',
  description: 'Contoh Deskripsi',
  submit_in_zone: true,
  default: true
  fields: [
    {...},
    {...},
    ...
  ],
}

JSON object form fields sample:

  1. Text Field
{
  id: '7231942686725',
  label: 'Text field 1',
  description: 'description',
  required: true,
  type: 'text',
  minLength: 0,
  maxLength: 24,
}
  1. Checkbox
{
  id: '23565229205',
  label: 'Checkboxes',
  description: 'description',
  required: false,
  minChecked: 1,
  maxChecked: 3,
  group: [
    {
      label: 'Option #1'
    },
    {
      label: 'Option #2'
    },
    {
      label: 'Option #3'
    }
  ],
  type: 'checkbox_group'
}
  1. Radio Button
{
  id: '2356760777462',
  label: 'Radiobuttons',
  description: 'description',
  required: true,
  options: [
    {
      label: 'Option #1'
    },
    {
      label: 'Option #2'
    },
    {
      label: 'Option #3'
    }
  ],
  type: 'radio_group'
}
  1. Dropdown
{
  id: '2357109577409',
  label: 'Dropdown',
  description: 'description',
  required: false,
  options: [
    {
      label: 'Option #1'
    },
    {
      label: 'Option #2'
    },
    {
      label: 'Option #3'
    }
  ],
  type: 'dropdown'
}
  1. Date
{
  id: '2357265606749',
  label: 'Date',
  description: 'description',
  required: false,
  disableFuture: false,
  disablePast: true,
  type: 'date'
}
  1. Separator
{
  id: '23575153539',
  label: 'Separator',
  description: 'description',
  type: 'separator'
}
  1. Rating
{
  id: '2357523970968',
  label: 'Rating',
  description: 'description',
  required: false,
  maxStars: 5,
  type: 'rating'
}
  1. File
{
  id: '2357526469860',
  label: File',
  description: 'description',
  required: true,
  maxFiles: 6,
  maxFileSize: 10485760,
  minFileSize: 128,
  fileMinSizeType: 'MB',
  fileMaxSizeType: 'MB',
  allowedExtensions: [
    'csv',
    'doc',
    'docx'
  ],
  type: 'file'
}
  1. Image
{
  id: '2357527652279',
  label: 'Image',
  description: 'description',
  required: false,
  maxFiles: 6,
  allowGalleryUpload: true,
  type: 'photo'
}
  1. Signature
{
  id: '2357528685219',
  label: 'Signature',
  description: 'description',
  required: false,
  type: 'signature'
}
  1. Time
  1. Barcode
  1. Sketch
  1. Yes/No
  1. Integer

Error Handling Module

Description

Error Handling Module

To-do List

  • Create error handling classes, including Worx error code enum definition, error handler class, and error response class.
  • List current available error code enum.
  • Create error response builder.
  • Create validation error class for Form validation.

Export API

Description

Export API on the submission page. Download the last 1000 entries with all pre-signed URLs for each file—download option as CSV or Xls.
image

source;submission date;submission address;form label;form description;field 1;field 2;....
web browser;20-09-2022 15:06:75;rumah sana;my form;my form description;isian 1;isian 2;...

User Module

Description

User Module

To-do List

  • Create User table definition, entity class, and repository class
  • Implement CRUD API on User entity
  • Implement Auth API (sign up, sign in, logout)

File Module

Description

File Module

To-do List

  • Create file storage interface
  • Create S3 compatible implementation (minio, etc)

User relation to Device entity

User relation to Device entity, either with userId or by organization code.

  • On create, assign user to device
  • On fetch/get/search, check userId/organization code -> need authContext

Implement Group Search API with Pagination

Description

Implement Group Search API with Pagination. Please use the POST method and path groups/search.

Reference

  • Form Template Search API
    @PostMapping("search")
    public ResponseEntity<Page<FormTemplateDTO>> search(
    @RequestBody @Valid FormTemplateSearchRequest request,
    @ParameterObject Pageable pageable) {
    Page<FormTemplate> templates = templateService.search(request, pageable);
    List<FormTemplateDTO> dtos = templates.stream()
    .map(templateService::toDTO)
    .collect(Collectors.toList());
    Page<FormTemplateDTO> page = new BasePageResponse<>(dtos, templates.getPageable(), templates.getTotalElements());
    return ResponseEntity.status(HttpStatus.OK)
    .body(page);
    }
  • Form Template Submission Count Specification
    public Specification<FormTemplate> submissionCountEqualTo(Integer submissionCount) {
    return (root, query, cb) -> {
    Root<FormTemplate> template = root;
    Subquery<FormTemplate> subquery = query.subquery(FormTemplate.class);
    Root<FormTemplate> subroot = subquery.from(FormTemplate.class);
    Join<Form, FormTemplate> formSubmission = subroot.join(FormTemplate_.FORMS);
    subquery.select(formSubmission.get(Form_.TEMPLATE).get(FormTemplate_.ID))
    .groupBy(formSubmission.get(Form_.TEMPLATE).get(FormTemplate_.ID));
    if (submissionCount.equals(0)) {
    return cb.in(template.get(FormTemplate_.ID)).value(subquery).not();
    }
    subquery.having(
    cb.equal(
    cb.count(formSubmission.get(Form_.TEMPLATE).get(FormTemplate_.ID)),
    submissionCount));
    return cb.in(template.get(FormTemplate_.ID)).value(subquery);
    };
    }
  • Having MySQL https://www.w3schools.com/sql/sql_having.asp

Rework File API, use nanoid instead of file id on every transaction.

Description

Rework File API, use nanoid instead of file id on every transaction.

To-do List

  • Add name, media_id, and original_name columns to File table. The original_name indicates its original filename, which will be submitted when the client asks for a pre-signed URL. The media_id is the generated id from the server. And the name column is the generated name from the server.
  • Generate media_id and name with the nanoid library. The media_id format is {16 characters nanoid}. Then, the filename format is {media_id}.{file extension}
    public class UrlUtils {
    private static final char[] DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    .toCharArray();
    private UrlUtils() {
    throw new IllegalStateException("Utility class");
    }
    public static String generateUrlCode() {
    return NanoIdUtils.randomNanoId(
    NanoIdUtils.DEFAULT_NUMBER_GENERATOR,
    DEFAULT_ALPHABET,
    NanoIdUtils.DEFAULT_SIZE);
    }
  • Change get (upload) pre-signed URL API for web (GET /media/presigned-url) and mobile (GET /mobile/media/presigned-url) flow to generate the media_id and the name value. Then, return FileResponse which contains all properties of File entity.
    {
      "id": 1,
      "media_id": "abcdefghijklmnop"
      "name": "abcdefghijklmnop.xls"
      "url": "{upload pre-signed url}",
      "path": "{media path}",
      "mime_type": "{mime_type}",
      "size": "{size}"
    }
  • Change download pre-signed URL API for web (GET /media/files) and mobile (GET /mobile/media/download-presigned-url) parameter to use media_id instead of fileId. Then, return FileResponse which contains all properties of File entity.

Guideline

This issue is just documentation for the code, format, folder, and file conventions.

  1. Components:
  • please use Material UI components as the core components
  • please use Material UI Typography component to replace any HTML text elements such as h1, h2, h3, h4, h5, h6, and p
  • please use Material UI Box component to replace any HTML container elements such as div and img
  1. Styles:
  • please use useStyles from makeStyles for static styles instead of plain CSS
  • please only use sx prop for dynamic styles
  1. File extension:
  • please use .jsx for component files
  • please use .js for style files
  1. Global state management tool:
  • please use React Context API instead of using Redux or React Redux
  1. Branch:
  • "develop" branch is the main branch for developing the app
  • "master" is the branch for deploying the app into the development environment
  • creating a new branch (your own working branch) must come from the "develop" branch
  • every morning or every time before creating a pull request from your branch you should merge the main branch ("develop" branch) into your branch
  1. Pull request:
  • make sure there is no error/crash and fewer warning messages before you create a new pull request
  • before the reviewers and assignees merge a pull request, make sure to test the pull request on their own local computer
  • don't merge a pull request that contains errors/crashes
  • please write every detail you made in each pull request
  1. Environment keys:
  • please copy and paste everything inside your .env into .env.example
  • don't push the .env file into Git
  1. Code writing:
  • every variable, function, and file must be written in English
  • give a brief comment for every function and component
  • every color/background color style must be taken from theme, please don't write the hex code manually, and please don't access the color constant manually
  • the components folder is only dedicated for the general components (components used by multiple pages)
  • please sort by alphabet the "import statements" and don't forget to group them
  • every spacing (padding or margin) and size (height or width) must be multiple of 4px
  • don't write import React from 'react' because it's not needed
  • styles inside useStyles from makeStyles are written top to bottom by the implementation order
  • please write Icon first followed by the name for importing the icon from the MUI
  • every asset from the Figma is exported using the same file format as the original asset

Resources:

  1. Figma files: https://www.figma.com/file/ohODkjvYtsC2G4mwlwaC5k/Worx.id

Dashboard API

Description

Implement API to provide data to the Dashboard page.
image

API Specification

POST /dashboard-stats

Request parameter

Name Description Type
from from date range date
to to date range date

Request Body

Structure

{
    "template_id": 2,
    "device_id": 2
}
{
    "template_id": 2
}
{
    "device_id": 2
}

Response

Structure

{
    "success": true,
    "list": [
        chartEntry1,
        chartEntry2
    ]
}

Chart Entry Structure

{
    "date": "yyyy-MM-dd",
    "count": 2
}

Deprecated `SecurityConfiguration` Implementation

Description

Update deprecated SecurityConfiguration implementation.

@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

Reference(s)

Geocoder API

Description

Implement Geocoder API. Use Google API provider.

geocoding.
reverse-geocoding.

Create New Team Mobile API

Description

Implement Create New Team Mobile API.
This API is the mobile counterpart of this user register API /api/users/register.

Please also change all the deviceCode headers on all mobile controllers to use camel case (deviceCode instead of device_code).

Specification

POST /mobile/create-new-team (Separate controller)
Request body

{
  "fullname": "string",
  "password": "string",
  "email": "string",
  "phoneNo": "string",
  "country": "string",
  "organization_name": "string"
}

Group Module

Description

Group Module

To-do List

  • Create Group table definition, entity class, and repository class
  • Implement CRUD API on Group entity

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.