First commit
This commit is contained in:
389
tapit-backend/auth.go
Normal file
389
tapit-backend/auth.go
Normal file
@@ -0,0 +1,389 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
"github.com/jinzhu/gorm"
|
||||
"math/rand"
|
||||
"time"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type UserJson struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
SecretCode string `json:"secretCode"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string
|
||||
PasswordHash string
|
||||
Name string
|
||||
Email string
|
||||
}
|
||||
|
||||
|
||||
type Session struct {
|
||||
gorm.Model
|
||||
SessionID string
|
||||
UserID uint
|
||||
}
|
||||
|
||||
func (tapit *Tapit) login(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "POST" {
|
||||
// start doing work
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
userJson := UserJson{}
|
||||
err = json.Unmarshal(requestBody, &userJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
currUser := User{}
|
||||
tapit.db.Where(&User{Username:userJson.Username}).First(&currUser)
|
||||
// user exists
|
||||
if currUser.Username == userJson.Username {
|
||||
// checking hash...
|
||||
if checkPasswordHash(currUser.PasswordHash, userJson.Password) {
|
||||
userJson.Password = ""
|
||||
userJson.Name = currUser.Name
|
||||
userJson.Email = currUser.Email
|
||||
messageOutput := NotificationJson{
|
||||
Text: "Successfully logged in!",
|
||||
ResultType: "success",
|
||||
Payload: userJson,
|
||||
}
|
||||
jsonResults, err := json.Marshal(messageOutput)
|
||||
if err!=nil {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
authCookie := tapit.generateCookie(currUser)
|
||||
http.SetCookie(w, &authCookie)
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Username or password is incorrect", nil)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
tapit.hashPassword("nothing-to-do-waste-time")
|
||||
notifyPopup(w, r, "failure", "Username or password is incorrect", nil)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) register(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "POST" {
|
||||
// start doing work
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
userJson := UserJson{}
|
||||
err = json.Unmarshal(requestBody, &userJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// checks if secret code is correct
|
||||
if userJson.SecretCode != tapit.globalSettings.secretRegistrationCode {
|
||||
messageOutput := NotificationJson{
|
||||
Text: "Your secret code is incorrect. Please try again.",
|
||||
ResultType: "failure",
|
||||
}
|
||||
jsonResults, err := json.Marshal(messageOutput)
|
||||
if err!=nil {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
http.Error(w, string(jsonResults), 200)
|
||||
return
|
||||
}
|
||||
|
||||
//check if user exists
|
||||
currUser := User{}
|
||||
tapit.db.Where(&User{Username: userJson.Username}).First(&currUser)
|
||||
if currUser.Username != "" {
|
||||
messageOutput := NotificationJson{
|
||||
Text: "Username exists. Please choose another one.",
|
||||
ResultType: "failure",
|
||||
}
|
||||
jsonResults, err := json.Marshal(messageOutput)
|
||||
if err!=nil {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
http.Error(w, string(jsonResults), 200)
|
||||
return
|
||||
}
|
||||
|
||||
//input validation that all are filled
|
||||
if userJson.Username == "" || userJson.Name == "" || userJson.Email == "" || userJson.Password == "" {
|
||||
messageOutput := NotificationJson{
|
||||
Text: "Please fill up all the information",
|
||||
ResultType: "failure",
|
||||
}
|
||||
jsonResults, err := json.Marshal(messageOutput)
|
||||
if err!=nil {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
http.Error(w, string(jsonResults), 200)
|
||||
return
|
||||
}
|
||||
|
||||
// creates user...
|
||||
currUser.Username = userJson.Username
|
||||
currUser.Name = userJson.Name
|
||||
currUser.Email = userJson.Email
|
||||
currUser.PasswordHash, _ = tapit.hashPassword(userJson.Password)
|
||||
var jsonResults []byte
|
||||
if (tapit.db.NewRecord(&currUser)) {
|
||||
tapit.db.Create(&currUser)
|
||||
userJson.Password = ""
|
||||
messageOutput := NotificationJson{
|
||||
Text: "Successfully registered!",
|
||||
ResultType: "success",
|
||||
Payload: userJson,
|
||||
}
|
||||
jsonResults, err = json.Marshal(messageOutput)
|
||||
if err!=nil {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
authCookie := tapit.generateCookie(currUser)
|
||||
http.SetCookie(w, &authCookie)
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) logout(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "POST" {
|
||||
// start doing work
|
||||
var currSession Session
|
||||
authCookie, err := r.Cookie("tapitsession")
|
||||
if err!=nil {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
}
|
||||
authCookieStr := authCookie.String()[13:]
|
||||
tapit.db.Where(&Session{SessionID: authCookieStr}).First(&currSession)
|
||||
if currSession.SessionID != authCookieStr {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
} else {
|
||||
tapit.db.Delete(&currSession)
|
||||
messageOutput := NotificationJson{
|
||||
Text: "Successfully logged out",
|
||||
ResultType: "success",
|
||||
Payload: "",
|
||||
}
|
||||
jsonResults, err := json.Marshal(messageOutput)
|
||||
if err!=nil {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
delCookie := tapit.deleteCookie()
|
||||
http.SetCookie(w, &delCookie)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) authenticationHandler(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var currSession Session
|
||||
authCookie, err := r.Cookie("tapitsession")
|
||||
if err!=nil {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
}
|
||||
authCookieStr := authCookie.String()[13:]
|
||||
tapit.db.Where(&Session{SessionID: authCookieStr}).First(&currSession)
|
||||
if currSession.SessionID != authCookieStr {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
} else {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) generateCookie(user User) http.Cookie {
|
||||
newToken := generateToken()
|
||||
newSession := Session{}
|
||||
tapit.db.Where(&Session{SessionID: newToken}).First(&newSession)
|
||||
for newToken == newSession.SessionID {
|
||||
newToken = generateToken()
|
||||
tapit.db.Where(&Session{SessionID: newToken}).First(&newSession)
|
||||
}
|
||||
newSession.UserID = user.ID
|
||||
newSession.SessionID = newToken
|
||||
tapit.db.NewRecord(&newSession)
|
||||
tapit.db.Create(&newSession)
|
||||
|
||||
newCookie := http.Cookie {
|
||||
Name: "tapitsession",
|
||||
Value: newToken,
|
||||
Path: "/",
|
||||
MaxAge: 60*60*24*365*10,
|
||||
HttpOnly: true,
|
||||
}
|
||||
return newCookie
|
||||
}
|
||||
|
||||
func (tapit *Tapit) deleteCookie() http.Cookie {
|
||||
newCookie := http.Cookie {
|
||||
Name: "tapitsession",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: 0,
|
||||
HttpOnly: true,
|
||||
}
|
||||
return newCookie
|
||||
}
|
||||
|
||||
func generateToken() string {
|
||||
var tokenResult strings.Builder
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var r int
|
||||
tokenCharset := "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
for i:=0; i<16; i++ {
|
||||
r = rand.Int() % len(tokenCharset)
|
||||
tokenResult.WriteRune(rune(tokenCharset[r]))
|
||||
}
|
||||
return tokenResult.String()
|
||||
}
|
||||
|
||||
func (tapit *Tapit) hashPassword(password string) (string, error) {
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), tapit.globalSettings.bcryptCost)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
func checkPasswordHash(hash string, password string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (tapit *Tapit) myselfHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.checkUser(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "PUT" {
|
||||
tapit.updateUser(w, r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) checkUser(w http.ResponseWriter, r *http.Request) {
|
||||
var currSession Session
|
||||
authCookie, err := r.Cookie("tapitsession")
|
||||
if err!=nil {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
}
|
||||
authCookieStr := authCookie.String()[13:]
|
||||
tapit.db.Where(&Session{SessionID: authCookieStr}).First(&currSession)
|
||||
if currSession.SessionID != authCookieStr {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
} else {
|
||||
currUser := User{}
|
||||
searchUser := User{}
|
||||
searchUser.ID = currSession.UserID
|
||||
tapit.db.Where(searchUser).First(&currUser)
|
||||
currentUserJson := UserJson{}
|
||||
currentUserJson.Username = currUser.Username
|
||||
currentUserJson.Name = currUser.Name
|
||||
currentUserJson.Email = currUser.Email
|
||||
jsonResults, err := json.Marshal(currentUserJson)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) updateUser(w http.ResponseWriter, r *http.Request) {
|
||||
var currSession Session
|
||||
authCookie, err := r.Cookie("tapitsession")
|
||||
if err!=nil {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
}
|
||||
authCookieStr := authCookie.String()[13:]
|
||||
tapit.db.Where(&Session{SessionID: authCookieStr}).First(&currSession)
|
||||
if currSession.SessionID != authCookieStr {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
} else {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
userJson := UserJson{}
|
||||
err = json.Unmarshal(requestBody, &userJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
currUser := User{}
|
||||
searchUser := User{}
|
||||
searchUser.ID = currSession.UserID
|
||||
tapit.db.Where(searchUser).First(&currUser)
|
||||
if currUser.ID == currSession.UserID && currUser.Username == userJson.Username {
|
||||
currUser.Name = userJson.Name
|
||||
currUser.Email = userJson.Email
|
||||
currUser.PasswordHash, _ = tapit.hashPassword(userJson.Password)
|
||||
tapit.db.Save(&currUser)
|
||||
userJson.Password = ""
|
||||
// writing output
|
||||
notifyPopup(w, r, "success", "Successfully changed profile!", userJson)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "Not authorised", 401)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
540
tapit-backend/campaign.go
Normal file
540
tapit-backend/campaign.go
Normal file
@@ -0,0 +1,540 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/gorilla/mux"
|
||||
"sync"
|
||||
"time"
|
||||
"net/http"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Campaign struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
FromNumber string
|
||||
Size int
|
||||
CurrentStatus string // enum Running, Paused, Completed, Not Started
|
||||
PhonebookId uint
|
||||
TextTemplateId uint
|
||||
WebTemplateId uint
|
||||
ProviderTag string
|
||||
Jobs []Job `gorm:"foreignkey:CampaignId"`
|
||||
}
|
||||
|
||||
type CampaignComms struct {
|
||||
Campaign Campaign
|
||||
Action string // enum run, stop
|
||||
}
|
||||
|
||||
type JobComms struct {
|
||||
Job Job
|
||||
Action string // enum run, stop
|
||||
}
|
||||
|
||||
type CampaignJson struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
FromNumber string `json:"fromNumber"`
|
||||
Size int `json:"size"`
|
||||
CurrentStatus string `json:"currentStatus"`
|
||||
CreateDate time.Time `json:"createDate"`
|
||||
PhonebookId uint `json:"phoneBookId"`
|
||||
TextTemplateId uint `json:"textTemplateId"`
|
||||
WebTemplateId uint `json:"webTemplateId"`
|
||||
ProviderTag string `json:"providerTag"`
|
||||
Jobs []JobJson `json:"jobs"`
|
||||
}
|
||||
|
||||
type Job struct {
|
||||
gorm.Model
|
||||
CampaignId uint
|
||||
CurrentStatus string // enum Failed, Queued, Sent, Delivered, Not Started
|
||||
TimeSent time.Time
|
||||
ProviderTag string
|
||||
AccSID string
|
||||
AuthToken string
|
||||
BodyText string
|
||||
FromNum string
|
||||
ToNum string
|
||||
ResultStr string
|
||||
MessageSid string
|
||||
}
|
||||
|
||||
type JobJson struct {
|
||||
Id uint `json:"id"`
|
||||
CurrentStatus string `json:"currentStatus"`
|
||||
TimeSent time.Time `json:"timeSent"`
|
||||
FromNum string `json:"fromNum"`
|
||||
ToNum string `json:"toNum"`
|
||||
}
|
||||
|
||||
type TwilioMessageJson struct {
|
||||
AccountSid string `json:"account_sid"`
|
||||
ApiVersion string `json:"api_version"`
|
||||
Body string `json:"body"`
|
||||
DateCreated string `json:"date_created"`
|
||||
DateSent string `json:"date_sent"`
|
||||
DateUpdated string `json:"date_updated"`
|
||||
Direction string `json:"direction"`
|
||||
ErrorCode string `json:"error_code"`
|
||||
ErrorMessage string `json:"error_message"`
|
||||
From string `json:"from"`
|
||||
MessagingServiceSid string `json:"messaging_service_sid"`
|
||||
NumMedia string `json:"num_media"`
|
||||
NumSegments string `json:"num_segments"`
|
||||
Price string `json:"price"`
|
||||
PriceUnit string `json:"price_unit"`
|
||||
Sid string `json:"sid"`
|
||||
Status string `json:"status"`
|
||||
SubResourceUri SubResourceUriJson `json:"subresource_uris"`
|
||||
To string `json:"to"`
|
||||
Uri string `json:"uri"`
|
||||
}
|
||||
|
||||
type SubResourceUriJson struct {
|
||||
Media string `json:"media"`
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getCampaigns(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "POST" {
|
||||
tapit.createCampaign(w, r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getCampaigns(w http.ResponseWriter, r *http.Request) {
|
||||
var campaigns []Campaign
|
||||
tapit.db.Find(&campaigns)
|
||||
jsonResults, err := json.Marshal(campaignsToJson(campaigns))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func campaignsToJson(campaigns []Campaign) []CampaignJson {
|
||||
var results []CampaignJson
|
||||
for _, currCampaign := range campaigns {
|
||||
var currJson CampaignJson
|
||||
currJson.Id = currCampaign.ID
|
||||
currJson.Name = currCampaign.Name
|
||||
currJson.Size = currCampaign.Size
|
||||
currJson.FromNumber = currCampaign.FromNumber
|
||||
currJson.CurrentStatus = currCampaign.CurrentStatus
|
||||
currJson.CreateDate = currCampaign.CreatedAt
|
||||
currJson.PhonebookId = currCampaign.PhonebookId
|
||||
currJson.TextTemplateId = currCampaign.TextTemplateId
|
||||
currJson.WebTemplateId = currCampaign.WebTemplateId
|
||||
currJson.ProviderTag = currCampaign.ProviderTag
|
||||
|
||||
results = append(results, currJson)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
func (tapit *Tapit) createCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
var newCampaignJson CampaignJson
|
||||
err = json.Unmarshal(requestBody, &newCampaignJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if newCampaignJson.Name != "" {
|
||||
var newCampaign Campaign
|
||||
|
||||
// populate details to be used later
|
||||
var newRecords []PhoneRecord
|
||||
var newTextTemplateBody string
|
||||
var newAccSID string
|
||||
var newAuthToken string
|
||||
newRecords = tapit.getSpecificPhonebook(newCampaignJson.PhonebookId).Records
|
||||
newTextTemplateBody = tapit.getSpecificTextBody(newCampaignJson.TextTemplateId)
|
||||
if newCampaignJson.ProviderTag == "twilio" {
|
||||
var twilioProvider TwilioProvider
|
||||
tapit.db.Last(&twilioProvider)
|
||||
|
||||
newAccSID = twilioProvider.AccountSID
|
||||
newAuthToken = twilioProvider.AuthToken
|
||||
}
|
||||
|
||||
// update static details
|
||||
newCampaign.Name = newCampaignJson.Name
|
||||
newCampaign.Size = len(newRecords)
|
||||
newCampaign.CurrentStatus = "Not Started"
|
||||
|
||||
newCampaign.FromNumber = newCampaignJson.FromNumber
|
||||
newCampaign.PhonebookId = newCampaignJson.PhonebookId
|
||||
newCampaign.TextTemplateId = newCampaignJson.TextTemplateId
|
||||
newCampaign.WebTemplateId = newCampaignJson.WebTemplateId
|
||||
newCampaign.ProviderTag = newCampaignJson.ProviderTag
|
||||
|
||||
// update records
|
||||
for _, record := range newRecords {
|
||||
var newJob Job
|
||||
newJob.CurrentStatus = "Not Started"
|
||||
newJob.ProviderTag = newCampaign.ProviderTag
|
||||
newJob.AccSID = newAccSID
|
||||
newJob.AuthToken = newAuthToken
|
||||
newJob.FromNum = newCampaign.FromNumber
|
||||
|
||||
// interpreting records
|
||||
var newBodyText string
|
||||
newJob.ToNum = record.PhoneNumber
|
||||
newBodyText = newTextTemplateBody
|
||||
newBodyText = strings.Replace(newBodyText, "{firstName}", record.FirstName, -1)
|
||||
newBodyText = strings.Replace(newBodyText, "{lastName}", record.LastName, -1)
|
||||
newBodyText = strings.Replace(newBodyText, "{alias}", record.Alias, -1)
|
||||
newBodyText = strings.Replace(newBodyText, "{phoneNumber}", record.PhoneNumber, -1)
|
||||
|
||||
newJob.BodyText = newBodyText
|
||||
|
||||
// saving it
|
||||
newCampaign.Jobs = append(newCampaign.Jobs, newJob)
|
||||
}
|
||||
|
||||
// update database
|
||||
tapit.db.NewRecord(&newCampaign)
|
||||
tapit.db.Create(&newCampaign)
|
||||
if newCampaign.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create campaign", nil)
|
||||
return
|
||||
}
|
||||
newCampaignJson.Id = newCampaign.ID
|
||||
newCampaignJson.CreateDate = newCampaign.CreatedAt
|
||||
newCampaignJson.Size = newCampaign.Size
|
||||
newCampaignJson.CurrentStatus = newCampaign.CurrentStatus
|
||||
|
||||
notifyPopup(w, r, "success", "Successfully added new campaign", newCampaignJson)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Please enter the campaign name", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleSpecificCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "PUT" {
|
||||
// not implmented -- complexity in changing campaign perimeters
|
||||
// tapit.updateCampaign(w, r)
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
} else if strings.ToUpper(r.Method) == "DELETE" {
|
||||
tapit.deleteCampaign(w,r)
|
||||
return
|
||||
} else if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getCampaign(w,r)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getSpecificCampaign(id uint) Campaign {
|
||||
var campaign Campaign
|
||||
var jobs []Job
|
||||
|
||||
var dbSearchCampaign Campaign
|
||||
dbSearchCampaign.ID = id
|
||||
tapit.db.Where(&dbSearchCampaign).First(&campaign)
|
||||
|
||||
var dbSearchJob Job
|
||||
dbSearchJob.CampaignId = id
|
||||
tapit.db.Where(&dbSearchJob).Find(&jobs)
|
||||
|
||||
campaign.Jobs = jobs
|
||||
return campaign
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
phonebook := tapit.getSpecificCampaign(uint(tempID))
|
||||
|
||||
jsonResults, err := json.Marshal(campaignToJson(phonebook))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func campaignToJson(campaign Campaign) CampaignJson {
|
||||
var cJson CampaignJson
|
||||
cJson.Id = campaign.ID
|
||||
cJson.Name = campaign.Name
|
||||
cJson.FromNumber = campaign.FromNumber
|
||||
cJson.Size = campaign.Size
|
||||
cJson.CurrentStatus = campaign.CurrentStatus
|
||||
cJson.PhonebookId = campaign.PhonebookId
|
||||
cJson.TextTemplateId = campaign.TextTemplateId
|
||||
cJson.WebTemplateId = campaign.WebTemplateId
|
||||
cJson.ProviderTag = campaign.ProviderTag
|
||||
|
||||
// iterating jobs
|
||||
for _, job := range campaign.Jobs {
|
||||
var currJson JobJson
|
||||
currJson.CurrentStatus = job.CurrentStatus
|
||||
currJson.TimeSent = job.TimeSent
|
||||
currJson.FromNum = job.FromNum
|
||||
currJson.ToNum = job.ToNum
|
||||
|
||||
cJson.Jobs = append(cJson.Jobs, currJson)
|
||||
}
|
||||
return cJson
|
||||
}
|
||||
|
||||
func (tapit *Tapit) deleteCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var campaign Campaign
|
||||
|
||||
// get phonebook
|
||||
var dbSearchCampaign Campaign
|
||||
dbSearchCampaign.ID = uint(tempID)
|
||||
tapit.db.Where(&dbSearchCampaign).First(&campaign)
|
||||
|
||||
if campaign.ID == uint(tempID) {
|
||||
// finally delete it
|
||||
tapit.db.Delete(&campaign)
|
||||
notifyPopup(w, r, "success", "Successfully deleted campaign", nil)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleStartCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.startCampaign(w,r)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleStopCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.stopCampaign(w,r)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (tapit *Tapit) startCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var campaign Campaign
|
||||
|
||||
campaign = tapit.getSpecificCampaign(uint(tempID))
|
||||
|
||||
if campaign.ID == uint(tempID) && campaign.CurrentStatus != "Running" && campaign.CurrentStatus != "Completed" {
|
||||
// finally start new thread and start working
|
||||
go tapit.workerCampaign(campaign)
|
||||
campaign.CurrentStatus = "Running"
|
||||
tapit.db.Save(&campaign)
|
||||
jsonResults := campaignToJson(campaign)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "success", "Started campaign", jsonResults)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) stopCampaign(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var campaign Campaign
|
||||
|
||||
campaign = tapit.getSpecificCampaign(uint(tempID))
|
||||
|
||||
if campaign.ID == uint(tempID) && campaign.CurrentStatus == "Running" {
|
||||
var campaignComms CampaignComms
|
||||
campaignComms.Action = "stop"
|
||||
campaignComms.Campaign = campaign
|
||||
tapit.campaignChan <- campaignComms
|
||||
|
||||
// notify
|
||||
notifyPopup(w, r, "success", "Paused campaign", nil)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) workerCampaign(campaign Campaign) {
|
||||
var campaignComms CampaignComms
|
||||
var jobChan chan JobComms
|
||||
var wg sync.WaitGroup
|
||||
|
||||
jobChan = make(chan JobComms, 1)
|
||||
for i:=0; i<tapit.globalSettings.threadsPerCampaign; i++ {
|
||||
wg.Add(1)
|
||||
go tapit.workerJob(jobChan, &wg)
|
||||
}
|
||||
|
||||
for _, job := range campaign.Jobs {
|
||||
select {
|
||||
case campaignComms = <-tapit.campaignChan:
|
||||
if campaignComms.Campaign.ID == campaign.ID {
|
||||
if campaignComms.Action == "stop" {
|
||||
// kill all
|
||||
for i:=0; i<tapit.globalSettings.threadsPerCampaign; i++ {
|
||||
var stopComms JobComms
|
||||
stopComms.Action = "stop"
|
||||
jobChan <- stopComms
|
||||
}
|
||||
// wait to end
|
||||
wg.Wait()
|
||||
|
||||
// get updated campaign
|
||||
var newCampaign Campaign
|
||||
var searchCampaign Campaign
|
||||
searchCampaign.ID = campaign.ID
|
||||
tapit.db.Where(&searchCampaign).First(&newCampaign)
|
||||
|
||||
// update campaign
|
||||
newCampaign.CurrentStatus = "Paused"
|
||||
tapit.db.Save(&newCampaign)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// not mine -- throw it back
|
||||
tapit.campaignChan<- campaignComms
|
||||
}
|
||||
default:
|
||||
if job.CurrentStatus == "Not Started" {
|
||||
var workComms JobComms
|
||||
workComms.Action = "run"
|
||||
workComms.Job = job
|
||||
jobChan <- workComms
|
||||
}
|
||||
}
|
||||
}
|
||||
for i:=0; i<tapit.globalSettings.threadsPerCampaign; i++ {
|
||||
var stopComms JobComms
|
||||
stopComms.Action = "stop"
|
||||
jobChan <- stopComms
|
||||
}
|
||||
|
||||
// wait to end
|
||||
wg.Wait()
|
||||
|
||||
// get updated campaign
|
||||
var newCampaign Campaign
|
||||
var searchCampaign Campaign
|
||||
searchCampaign.ID = campaign.ID
|
||||
tapit.db.Where(&searchCampaign).First(&newCampaign)
|
||||
|
||||
// update campaign
|
||||
newCampaign.CurrentStatus = "Completed"
|
||||
tapit.db.Save(&newCampaign)
|
||||
}
|
||||
|
||||
func (tapit *Tapit) workerJob(jobChan chan JobComms, wg *sync.WaitGroup) {
|
||||
var currentJob JobComms
|
||||
exitCode := false
|
||||
|
||||
for !exitCode {
|
||||
currentJob = <-jobChan
|
||||
if currentJob.Action != "stop" {
|
||||
if currentJob.Job.ProviderTag == "twilio" {
|
||||
|
||||
var resultJson []byte
|
||||
resultJson = tapit.twilioSend(currentJob.Job.AccSID, currentJob.Job.AuthToken, currentJob.Job.BodyText, currentJob.Job.FromNum, currentJob.Job.ToNum)
|
||||
currentJob.Job.ResultStr = string(resultJson)
|
||||
|
||||
var twilioResult TwilioMessageJson
|
||||
err := json.Unmarshal(resultJson, &twilioResult)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
currentJob.Job.CurrentStatus = "Failed"
|
||||
} else if twilioResult.Status == "queued" {
|
||||
currentJob.Job.MessageSid = twilioResult.Sid
|
||||
currentJob.Job.CurrentStatus = "Queued"
|
||||
} else if twilioResult.Status == "delivered" {
|
||||
currentJob.Job.MessageSid = twilioResult.Sid
|
||||
currentJob.Job.CurrentStatus = "Delivered"
|
||||
} else {
|
||||
currentJob.Job.CurrentStatus = "Failed"
|
||||
}
|
||||
|
||||
// redo until done
|
||||
tapit.db.Save(¤tJob.Job)
|
||||
}
|
||||
} else {
|
||||
exitCode = true
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
func (tapit *Tapit) clearRunningCampaigns() {
|
||||
var campaigns []Campaign
|
||||
var searchCampaign Campaign
|
||||
searchCampaign.CurrentStatus = "Running"
|
||||
tapit.db.Where(&searchCampaign).Find(&campaigns)
|
||||
|
||||
for _, campaign := range campaigns {
|
||||
campaign.CurrentStatus = "Paused"
|
||||
tapit.db.Save(&campaign)
|
||||
}
|
||||
}
|
||||
|
||||
143
tapit-backend/main.go
Normal file
143
tapit-backend/main.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||
"log"
|
||||
"github.com/gorilla/mux"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type Tapit struct {
|
||||
db *gorm.DB
|
||||
globalSettings GlobalSettings
|
||||
campaignChan chan CampaignComms
|
||||
}
|
||||
|
||||
type GlobalSettings struct {
|
||||
secretRegistrationCode string
|
||||
threadsPerCampaign int
|
||||
bcryptCost int
|
||||
maxRequestRetries int
|
||||
waitBeforeRetry int
|
||||
}
|
||||
|
||||
func generateFileHandler(path string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Header.Add("Cache-Control", "private, max-age=604800") // 7 days
|
||||
//r.Header.Add("Cache-Control", "private, max-age=1") // 1 sec -- debug
|
||||
http.ServeFile(w, r, path)
|
||||
}
|
||||
}
|
||||
|
||||
func iterateStatic(r *mux.Router, path string, startWebPath string) {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err!=nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if !f.IsDir() && f.Name()[0] != '.' {
|
||||
r.HandleFunc(startWebPath + f.Name(), generateFileHandler(path+"/"+f.Name()))
|
||||
log.Println(startWebPath + f.Name()+" added to path")
|
||||
} else if f.IsDir() && f.Name()[0] != '.' {
|
||||
iterateStatic(r, path + "/" + string(f.Name()), startWebPath + string(f.Name() + "/"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateRoutes(r *mux.Router, indexPath string, routes []string) {
|
||||
for _, route := range routes {
|
||||
r.HandleFunc(route, generateFileHandler(indexPath))
|
||||
log.Println(route+" added as route")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Setting up DB
|
||||
host := "postgres-tapit"
|
||||
db, err := gorm.Open("postgres", "sslmode=disable host=" + host + " port=5432 user=tapit dbname=tapit password=secret-tapit-password")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// DB Migrations
|
||||
db.AutoMigrate(&Session{})
|
||||
db.AutoMigrate(&User{})
|
||||
db.AutoMigrate(&TextTemplate{})
|
||||
db.AutoMigrate(&TwilioProvider{})
|
||||
db.AutoMigrate(&Phonebook{})
|
||||
db.AutoMigrate(&PhoneRecord{})
|
||||
db.AutoMigrate(&Campaign{})
|
||||
db.AutoMigrate(&Job{})
|
||||
|
||||
// Setting up Tapit app
|
||||
var tapit Tapit
|
||||
tapit.db = db
|
||||
tapit.globalSettings.secretRegistrationCode = "Super-Secret-Code"
|
||||
tapit.globalSettings.threadsPerCampaign = 2
|
||||
tapit.globalSettings.bcryptCost = 12
|
||||
tapit.globalSettings.maxRequestRetries = 5
|
||||
tapit.globalSettings.waitBeforeRetry = 1000
|
||||
|
||||
// Clear running campaigns & starting background jobs
|
||||
tapit.clearRunningCampaigns()
|
||||
go tapit.workerTwilioChecker()
|
||||
tapit.campaignChan = make(chan CampaignComms, 10)
|
||||
|
||||
// Setting up mux
|
||||
r := mux.NewRouter()
|
||||
|
||||
// Get current dir
|
||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Setting up static routes (frontend)
|
||||
iterateStatic(r, dir + "/static/", "/")
|
||||
routes := []string{
|
||||
"/",
|
||||
"/login",
|
||||
"/register",
|
||||
"/profile",
|
||||
"/campaign",
|
||||
"/campaign/new",
|
||||
"/campaign/{id}/view",
|
||||
"/phonebook",
|
||||
"/phonebook/new",
|
||||
"/phonebook/{id}/edit",
|
||||
"/text-template",
|
||||
"/text-template/new",
|
||||
"/text-template/{id}/edit",
|
||||
"/provider",
|
||||
}
|
||||
indexPath := dir + "/static/index.html"
|
||||
generateRoutes(r, indexPath, routes)
|
||||
|
||||
// Setting up API routes
|
||||
r.HandleFunc("/api/login", tapit.login)
|
||||
r.HandleFunc("/api/logout", tapit.logout)
|
||||
r.HandleFunc("/api/register", tapit.register)
|
||||
r.HandleFunc("/api/myself", tapit.authenticationHandler(tapit.myselfHandler))
|
||||
|
||||
r.Handle("/api/text-template",tapit.authenticationHandler(tapit.handleTextTemplate))
|
||||
r.Handle("/api/text-template/{id}",tapit.authenticationHandler(tapit.handleSpecificTextTemplate))
|
||||
r.Handle("/api/provider/twilio",tapit.authenticationHandler(tapit.handleTwilioProvider))
|
||||
r.Handle("/api/phonebook",tapit.authenticationHandler(tapit.handlePhonebook))
|
||||
r.Handle("/api/phonebook/{id}",tapit.authenticationHandler(tapit.handleSpecificPhonebook))
|
||||
r.Handle("/api/import-phonebook",tapit.authenticationHandler(tapit.importPhonebook))
|
||||
r.Handle("/api/campaign",tapit.authenticationHandler(tapit.handleCampaign))
|
||||
r.Handle("/api/campaign/{id}",tapit.authenticationHandler(tapit.handleSpecificCampaign))
|
||||
r.Handle("/api/campaign/{id}/start",tapit.authenticationHandler(tapit.handleStartCampaign))
|
||||
r.Handle("/api/campaign/{id}/pause",tapit.authenticationHandler(tapit.handleStopCampaign))
|
||||
|
||||
// Starting web server
|
||||
http.Handle("/", r)
|
||||
log.Println("Starting web server...")
|
||||
http.ListenAndServe(":8000", nil)
|
||||
}
|
||||
30
tapit-backend/notification.go
Normal file
30
tapit-backend/notification.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type NotificationJson struct {
|
||||
ResultType string `json:"resultType"` // success/failure/info
|
||||
Text string `json:"text"`
|
||||
Payload interface{} `json:"payload"`
|
||||
}
|
||||
|
||||
type Payload interface{}
|
||||
|
||||
func notifyPopup(w http.ResponseWriter, r *http.Request, resultType string, text string, payload Payload) {
|
||||
messageOutput := NotificationJson{
|
||||
ResultType: resultType,
|
||||
Text: text,
|
||||
Payload: payload,
|
||||
}
|
||||
jsonResults, err := json.Marshal(messageOutput)
|
||||
if err!=nil {
|
||||
http.Error(w, "Internal server error", 500)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
http.Error(w, string(jsonResults), 200)
|
||||
return
|
||||
}
|
||||
342
tapit-backend/phonebook.go
Normal file
342
tapit-backend/phonebook.go
Normal file
@@ -0,0 +1,342 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/tealeg/xlsx"
|
||||
"time"
|
||||
"net/http"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"log"
|
||||
"io"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type Phonebook struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
Size int
|
||||
Records []PhoneRecord `gorm:"foreignkey:PhonebookID"`
|
||||
}
|
||||
|
||||
type PhonebookJson struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Size int `json:"size"`
|
||||
CreateDate time.Time `json:"createDate"`
|
||||
Records []PhoneRecordJson `json:"records"`
|
||||
}
|
||||
|
||||
type PhoneRecord struct {
|
||||
gorm.Model
|
||||
PhonebookID uint
|
||||
FirstName string
|
||||
LastName string
|
||||
Alias string
|
||||
PhoneNumber string
|
||||
}
|
||||
|
||||
type PhoneRecordJson struct {
|
||||
Id uint `json:"id"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
Alias string `json:"alias"`
|
||||
PhoneNumber string `json:"phoneNumber"`
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handlePhonebook(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getPhonebooks(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "POST" {
|
||||
tapit.createPhonebook(w, r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getPhonebooks(w http.ResponseWriter, r *http.Request) {
|
||||
var phonebooks []Phonebook
|
||||
tapit.db.Find(&phonebooks)
|
||||
jsonResults, err := json.Marshal(phonebooksToJson(phonebooks))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func phonebooksToJson(pb []Phonebook) []PhonebookJson {
|
||||
var pbJson []PhonebookJson
|
||||
for _, currObj := range pb {
|
||||
var currPbJson PhonebookJson
|
||||
currPbJson.Id = currObj.ID
|
||||
currPbJson.Name = currObj.Name
|
||||
currPbJson.CreateDate = currObj.CreatedAt
|
||||
currPbJson.Size = currObj.Size
|
||||
|
||||
pbJson = append(pbJson, currPbJson)
|
||||
}
|
||||
return pbJson
|
||||
}
|
||||
|
||||
func (tapit *Tapit) createPhonebook(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
var newPhonebookJson PhonebookJson
|
||||
err = json.Unmarshal(requestBody, &newPhonebookJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if newPhonebookJson.Name != "" {
|
||||
var newPhonebook Phonebook
|
||||
|
||||
// update name & size
|
||||
newPhonebook.Name = newPhonebookJson.Name
|
||||
newPhonebook.Size = len(newPhonebookJson.Records)
|
||||
|
||||
// update records
|
||||
for _, record := range newPhonebookJson.Records {
|
||||
var newRecord PhoneRecord
|
||||
newRecord.FirstName = record.FirstName
|
||||
newRecord.LastName = record.LastName
|
||||
newRecord.Alias = record.Alias
|
||||
newRecord.PhoneNumber = record.PhoneNumber
|
||||
|
||||
newPhonebook.Records = append(newPhonebook.Records, newRecord)
|
||||
}
|
||||
|
||||
// update database
|
||||
tapit.db.NewRecord(&newPhonebook)
|
||||
tapit.db.Create(&newPhonebook)
|
||||
if newPhonebook.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create phonebook", nil)
|
||||
return
|
||||
}
|
||||
newPhonebookJson.Id = newPhonebook.ID
|
||||
newPhonebookJson.CreateDate = newPhonebook.CreatedAt
|
||||
newPhonebookJson.Size = newPhonebook.Size
|
||||
|
||||
notifyPopup(w, r, "success", "Successfully added new phonebook", newPhonebookJson)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Please enter the phonebook name", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getSpecificPhonebook(id uint) Phonebook {
|
||||
var phonebook Phonebook
|
||||
var records []PhoneRecord
|
||||
|
||||
var dbPhonebookSearch Phonebook
|
||||
dbPhonebookSearch.ID = id
|
||||
tapit.db.Where(&dbPhonebookSearch).First(&phonebook)
|
||||
|
||||
var dbSearchPhoneRecord PhoneRecord
|
||||
dbSearchPhoneRecord.PhonebookID = id
|
||||
tapit.db.Where(&dbSearchPhoneRecord).Find(&records)
|
||||
|
||||
phonebook.Records = records
|
||||
return phonebook
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getPhonebook(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
phonebook := tapit.getSpecificPhonebook(uint(tempID))
|
||||
|
||||
jsonResults, err := json.Marshal(phonebookToJson(phonebook))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func phonebookToJson(pb Phonebook) PhonebookJson {
|
||||
var pbJson PhonebookJson
|
||||
pbJson.Id = pb.ID
|
||||
pbJson.Name = pb.Name
|
||||
pbJson.CreateDate = pb.CreatedAt
|
||||
pbJson.Size = pb.Size
|
||||
for _, record := range pb.Records {
|
||||
var recordJson PhoneRecordJson
|
||||
recordJson.Id = record.ID
|
||||
recordJson.FirstName = record.FirstName
|
||||
recordJson.LastName = record.LastName
|
||||
recordJson.Alias = record.Alias
|
||||
recordJson.PhoneNumber = record.PhoneNumber
|
||||
|
||||
pbJson.Records = append(pbJson.Records, recordJson)
|
||||
}
|
||||
return pbJson
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleSpecificPhonebook(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "PUT" {
|
||||
tapit.updatePhonebook(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "DELETE" {
|
||||
tapit.deletePhonebook(w,r)
|
||||
} else if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getPhonebook(w,r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) updatePhonebook(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
var newPhonebookJson PhonebookJson
|
||||
err = json.Unmarshal(requestBody, &newPhonebookJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if newPhonebookJson.Name != "" {
|
||||
var newPhonebook Phonebook
|
||||
|
||||
// get current phonebook
|
||||
var dbSearchPhonebook Phonebook
|
||||
tapit.db.Where(&dbSearchPhonebook).First(&newPhonebook)
|
||||
|
||||
// update name & size
|
||||
newPhonebook.Name = newPhonebookJson.Name
|
||||
newPhonebook.Size = len(newPhonebookJson.Records)
|
||||
|
||||
// update records
|
||||
for _, record := range newPhonebookJson.Records {
|
||||
var newRecord PhoneRecord
|
||||
newRecord.FirstName = record.FirstName
|
||||
newRecord.LastName = record.LastName
|
||||
newRecord.Alias = record.Alias
|
||||
newRecord.PhoneNumber = record.PhoneNumber
|
||||
|
||||
newPhonebook.Records = append(newPhonebook.Records, newRecord)
|
||||
}
|
||||
|
||||
// update database
|
||||
tapit.db.Save(&newPhonebook)
|
||||
if newPhonebook.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create phonebook", nil)
|
||||
return
|
||||
}
|
||||
newPhonebookJson.Id = newPhonebook.ID
|
||||
newPhonebookJson.CreateDate = newPhonebook.CreatedAt
|
||||
newPhonebookJson.Size = newPhonebook.Size
|
||||
|
||||
notifyPopup(w, r, "success", "Successfully added new phonebook", newPhonebookJson)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Please enter the phonebook name", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) deletePhonebook(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var phonebook Phonebook
|
||||
|
||||
// get phonebook
|
||||
var dbSearchPhonebook Phonebook
|
||||
dbSearchPhonebook.ID = uint(tempID)
|
||||
tapit.db.Where(&dbSearchPhonebook).First(&phonebook)
|
||||
|
||||
if phonebook.ID == uint(tempID) {
|
||||
// finally delete it
|
||||
tapit.db.Delete(&phonebook)
|
||||
notifyPopup(w, r, "success", "Successfully deleted phonebook", nil)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) importPhonebook(w http.ResponseWriter, r *http.Request) {
|
||||
var records []PhoneRecordJson
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// 100 M reserved
|
||||
err = r.ParseMultipartForm(100000000)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
importFile, _, err := r.FormFile("phonebookFile")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
var buff bytes.Buffer
|
||||
|
||||
// use buffer to bytes
|
||||
io.Copy(&buff, importFile)
|
||||
fileBytes := buff.Bytes()
|
||||
|
||||
excelFile, err := xlsx.OpenBinary(fileBytes)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
for num, row := range excelFile.Sheet["import"].Rows {
|
||||
if num != 0 {
|
||||
var tempRecord PhoneRecordJson
|
||||
tempRecord.FirstName = row.Cells[0].Value
|
||||
tempRecord.LastName = row.Cells[1].Value
|
||||
tempRecord.Alias = row.Cells[2].Value
|
||||
tempRecord.PhoneNumber = row.Cells[3].Value
|
||||
records = append(records, tempRecord)
|
||||
}
|
||||
}
|
||||
jsonResults, err := json.Marshal(records)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
BIN
tapit-backend/tapit-backend
Executable file
BIN
tapit-backend/tapit-backend
Executable file
Binary file not shown.
240
tapit-backend/text-template.go
Normal file
240
tapit-backend/text-template.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/gorilla/mux"
|
||||
"time"
|
||||
"net/http"
|
||||
"strings"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type TextTemplate struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
TemplateStr string
|
||||
}
|
||||
|
||||
type TextTemplateJson struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
TemplateStr string `json:"templateStr"`
|
||||
CreateDate time.Time `json:"createDate"`
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleTextTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getTextTemplates(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "POST" {
|
||||
tapit.createTextTemplate(w, r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getTextTemplates(w http.ResponseWriter, r *http.Request) {
|
||||
textTemplates := []TextTemplate{}
|
||||
tapit.db.Find(&textTemplates)
|
||||
jsonResults, err := json.Marshal(textTemplatesToJson(textTemplates))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func textTemplatesToJson(textTemplates []TextTemplate) []TextTemplateJson {
|
||||
textTemplateJson := make([]TextTemplateJson, 0)
|
||||
for _, textTemplate := range textTemplates {
|
||||
var currentTextTemplateJson TextTemplateJson
|
||||
currentTextTemplateJson.Id = int(textTemplate.ID)
|
||||
currentTextTemplateJson.Name = textTemplate.Name
|
||||
currentTextTemplateJson.TemplateStr = textTemplate.TemplateStr
|
||||
currentTextTemplateJson.CreateDate = textTemplate.CreatedAt
|
||||
|
||||
textTemplateJson = append(textTemplateJson, currentTextTemplateJson)
|
||||
}
|
||||
return textTemplateJson
|
||||
}
|
||||
|
||||
func jsonToTextTemplate(textTemplateJson TextTemplateJson) TextTemplate {
|
||||
var resultTextTemplate TextTemplate
|
||||
resultTextTemplate.Name = textTemplateJson.Name
|
||||
resultTextTemplate.TemplateStr = textTemplateJson.TemplateStr
|
||||
return resultTextTemplate
|
||||
}
|
||||
|
||||
func (tapit *Tapit) createTextTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
// start doing work
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
newTextTemplateJson := TextTemplateJson{}
|
||||
err = json.Unmarshal(requestBody, &newTextTemplateJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if newTextTemplateJson.Name != "" && newTextTemplateJson.TemplateStr != "" {
|
||||
newTextTemplate := jsonToTextTemplate(newTextTemplateJson)
|
||||
tapit.db.NewRecord(&newTextTemplate)
|
||||
tapit.db.Create(&newTextTemplate)
|
||||
if newTextTemplate.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create text template", nil)
|
||||
return
|
||||
}
|
||||
newTextTemplateJson.Id = int(newTextTemplate.ID)
|
||||
newTextTemplateJson.CreateDate = newTextTemplate.CreatedAt
|
||||
|
||||
notifyPopup(w, r, "success", "Successfully added new text template", newTextTemplate)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Please fill in all details", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getSpecificTextBody(id uint) string {
|
||||
var textTemplate TextTemplate
|
||||
|
||||
var dbSearchTT TextTemplate
|
||||
dbSearchTT.ID = id
|
||||
tapit.db.Where(&dbSearchTT).First(&textTemplate)
|
||||
|
||||
return textTemplate.TemplateStr
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleSpecificTextTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "PUT" {
|
||||
tapit.updateTextTemplate(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "DELETE" {
|
||||
tapit.deleteTextTemplate(w,r)
|
||||
} else if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getTextTemplate(w,r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) updateTextTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
var newTextTemplateJson TextTemplateJson
|
||||
err = json.Unmarshal(requestBody, &newTextTemplateJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
if newTextTemplateJson.Name != "" {
|
||||
var newTextTemplate TextTemplate
|
||||
|
||||
// get current phonebook
|
||||
var dbSearchTT TextTemplate
|
||||
dbSearchTT.ID = uint(newTextTemplateJson.Id)
|
||||
tapit.db.Where(&dbSearchTT).First(&newTextTemplate)
|
||||
|
||||
if newTextTemplate.ID == uint(newTextTemplateJson.Id) {
|
||||
// update name & template
|
||||
newTextTemplate.Name = newTextTemplateJson.Name
|
||||
newTextTemplate.TemplateStr = newTextTemplateJson.TemplateStr
|
||||
|
||||
// update database
|
||||
tapit.db.Save(&newTextTemplate)
|
||||
if newTextTemplate.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to update phonebook", nil)
|
||||
return
|
||||
}
|
||||
newTextTemplateJson.Id = int(newTextTemplate.ID)
|
||||
newTextTemplateJson.CreateDate = newTextTemplate.CreatedAt
|
||||
|
||||
notifyPopup(w, r, "success", "Successfully updated text template", newTextTemplateJson)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Failed to update text template", nil)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
notifyPopup(w, r, "failure", "Please enter the phonebook name", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) deleteTextTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var textTemplate TextTemplate
|
||||
|
||||
// get tt
|
||||
var dbSearchTT TextTemplate
|
||||
dbSearchTT.ID = uint(tempID)
|
||||
tapit.db.Where(dbSearchTT).First(&textTemplate)
|
||||
|
||||
if textTemplate.ID == uint(tempID) {
|
||||
// finally delete it
|
||||
tapit.db.Delete(&textTemplate)
|
||||
notifyPopup(w, r, "success", "Successfully deleted phonebook", nil)
|
||||
return
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getTextTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
tempID, err := strconv.Atoi(vars["id"])
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// start working
|
||||
var textTemplate TextTemplate
|
||||
|
||||
// get tt
|
||||
var dbSearchTT TextTemplate
|
||||
dbSearchTT.ID = uint(tempID)
|
||||
tapit.db.Where(dbSearchTT).First(&textTemplate)
|
||||
|
||||
if textTemplate.ID == uint(tempID) {
|
||||
jsonResults, err := json.Marshal(textTemplateToJson(textTemplate))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func textTemplateToJson(textTemplate TextTemplate) TextTemplateJson {
|
||||
var result TextTemplateJson
|
||||
result.Id = int(textTemplate.ID)
|
||||
result.Name = textTemplate.Name
|
||||
result.TemplateStr = textTemplate.TemplateStr
|
||||
result.CreateDate = textTemplate.CreatedAt
|
||||
return result
|
||||
}
|
||||
215
tapit-backend/twilio.go
Normal file
215
tapit-backend/twilio.go
Normal file
@@ -0,0 +1,215 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"log"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TwilioProvider struct {
|
||||
gorm.Model
|
||||
AccountSID string
|
||||
AuthToken string
|
||||
}
|
||||
|
||||
type TwilioProviderJson struct {
|
||||
AccountSID string `json:"accountSID"`
|
||||
AuthToken string `json:"authToken"`
|
||||
}
|
||||
|
||||
func (tapit *Tapit) handleTwilioProvider(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.ToUpper(r.Method) == "GET" {
|
||||
tapit.getTwilioProvider(w, r)
|
||||
} else if strings.ToUpper(r.Method) == "POST" {
|
||||
tapit.updateTwilioProvider(w, r)
|
||||
} else {
|
||||
http.Error(w, "HTTP method not implemented", 400)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) getTwilioProvider(w http.ResponseWriter, r *http.Request) {
|
||||
var twilioProvider TwilioProvider
|
||||
tapit.db.Last(&twilioProvider)
|
||||
jsonResults, err := json.Marshal(twilioProviderToJson(twilioProvider))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(jsonResults)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (tapit *Tapit) updateTwilioProvider(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err:= ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
var newTwilioProviderJson TwilioProviderJson
|
||||
err = json.Unmarshal(requestBody, &newTwilioProviderJson)
|
||||
if err != nil {
|
||||
http.Error(w, "Bad request", 400)
|
||||
return
|
||||
}
|
||||
|
||||
// first check if already exist
|
||||
var twilioProvider TwilioProvider
|
||||
tapit.db.Last(&twilioProvider)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
// update twilioProvider
|
||||
twilioProvider.AccountSID = newTwilioProviderJson.AccountSID
|
||||
twilioProvider.AuthToken = newTwilioProviderJson.AuthToken
|
||||
|
||||
// does not exist
|
||||
if twilioProvider.ID == 0 {
|
||||
tapit.db.NewRecord(&twilioProvider)
|
||||
tapit.db.Create(&twilioProvider)
|
||||
|
||||
if twilioProvider.ID == 0 {
|
||||
notifyPopup(w, r, "failure", "Failed to create Twilio Provider", nil)
|
||||
return
|
||||
} else {
|
||||
notifyPopup(w, r, "success", "Twilio provider updated", newTwilioProviderJson)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// exists
|
||||
tapit.db.Save(&twilioProvider)
|
||||
notifyPopup(w, r, "success", "Twilio provider updated", newTwilioProviderJson)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func twilioProviderToJson(tProvider TwilioProvider) TwilioProviderJson {
|
||||
var results TwilioProviderJson
|
||||
results.AccountSID = tProvider.AccountSID
|
||||
results.AuthToken = tProvider.AuthToken
|
||||
return results
|
||||
}
|
||||
|
||||
func (tapit *Tapit) twilioSend(accSid string, accToken string, bodyText string, fromNum string, toNum string) []byte {
|
||||
// if burp proxy is necessary
|
||||
client := &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
method1 := "POST"
|
||||
url1 := "https://api.twilio.com/2010-04-01/Accounts/"+accSid+"/Messages.json"
|
||||
// making body
|
||||
params := url.Values{}
|
||||
params.Add("Body", bodyText)
|
||||
params.Add("From", fromNum)
|
||||
params.Add("To", toNum)
|
||||
body1 := strings.NewReader(params.Encode())
|
||||
log.Println(params.Encode())
|
||||
// making request
|
||||
newRequest1, err := http.NewRequest(method1, url1, body1)
|
||||
if err != nil {
|
||||
log.Fatal("Error in creating request")
|
||||
}
|
||||
|
||||
//basic auth with token
|
||||
newRequest1.SetBasicAuth(accSid, accToken)
|
||||
|
||||
//set headers
|
||||
newRequest1.Header.Add("Content-Type","application/x-www-form-urlencoded; charset=UTF-8")
|
||||
|
||||
// sending request
|
||||
res, err := client.Do(newRequest1)
|
||||
retriesLeft := tapit.globalSettings.maxRequestRetries
|
||||
for err != nil && retriesLeft > 0 {
|
||||
log.Println("Error in sending request")
|
||||
res, err = client.Do(newRequest1)
|
||||
retriesLeft -= 1
|
||||
time.Sleep(time.Duration(tapit.globalSettings.waitBeforeRetry) * time.Millisecond)
|
||||
}
|
||||
|
||||
// exit gracefully if can't
|
||||
if err!= nil {
|
||||
var emptyBytes []byte
|
||||
return emptyBytes
|
||||
}
|
||||
outputStr, _ := ioutil.ReadAll(res.Body)
|
||||
log.Println(string(outputStr))
|
||||
return outputStr
|
||||
}
|
||||
|
||||
func (tapit *Tapit) twilioCheck(accSid string, accToken string, messageSid string) []byte {
|
||||
client := &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
method1 := "GET"
|
||||
url1 := "https://api.twilio.com/2010-04-01/Accounts/"+accSid+"/Messages/"+messageSid+".json"
|
||||
body1 := strings.NewReader("")
|
||||
newRequest1, err := http.NewRequest(method1, url1, body1)
|
||||
|
||||
// authenticate
|
||||
newRequest1.SetBasicAuth(accSid, accToken)
|
||||
|
||||
// sending request
|
||||
res, err := client.Do(newRequest1)
|
||||
retriesLeft := tapit.globalSettings.maxRequestRetries
|
||||
for err != nil && retriesLeft > 0 {
|
||||
log.Println("Error in sending request")
|
||||
res, err = client.Do(newRequest1)
|
||||
retriesLeft -= 1
|
||||
time.Sleep(time.Duration(tapit.globalSettings.waitBeforeRetry) * time.Millisecond)
|
||||
}
|
||||
|
||||
// exit gracefully if can't
|
||||
if err!= nil {
|
||||
var emptyBytes []byte
|
||||
return emptyBytes
|
||||
}
|
||||
outputStr, _ := ioutil.ReadAll(res.Body)
|
||||
log.Println(string(outputStr))
|
||||
return outputStr
|
||||
}
|
||||
|
||||
func (tapit *Tapit) workerTwilioChecker() {
|
||||
// infinite loop to keep checking for queued jobs to check delivery status
|
||||
for true {
|
||||
// sleep 5 second per cycle
|
||||
time.Sleep(5000 * time.Millisecond)
|
||||
var pendJobs []Job
|
||||
|
||||
tapit.db.Where("provider_tag = ? AND (current_status = ? OR current_status = ?)", "twilio", "Queued", "Sent").Find(&pendJobs)
|
||||
|
||||
for _, job := range pendJobs {
|
||||
// sleep 100ms per job
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
resultJson := tapit.twilioCheck(job.AccSID, job.AuthToken, job.MessageSid)
|
||||
job.ResultStr = string(resultJson)
|
||||
|
||||
var twilioResult TwilioMessageJson
|
||||
err := json.Unmarshal(resultJson, &twilioResult)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
job.CurrentStatus = "Failed"
|
||||
} else if twilioResult.Status == "queued" {
|
||||
job.MessageSid = twilioResult.Sid
|
||||
job.CurrentStatus = "Queued"
|
||||
} else if twilioResult.Status == "sent" {
|
||||
job.MessageSid = twilioResult.Sid
|
||||
job.CurrentStatus = "Sent"
|
||||
} else if twilioResult.Status == "delivered" {
|
||||
job.MessageSid = twilioResult.Sid
|
||||
job.CurrentStatus = "Delivered"
|
||||
}
|
||||
tapit.db.Save(&job)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user