Skip to content

Instantly share code, notes, and snippets.

@zachary-russell
Created August 31, 2020 19:27
Show Gist options
  • Save zachary-russell/3bac3131c3927ba42210cbc04cbda552 to your computer and use it in GitHub Desktop.
Save zachary-russell/3bac3131c3927ba42210cbc04cbda552 to your computer and use it in GitHub Desktop.
FB Delete Users example
package main
import (
"bufio"
"bytes"
"context"
"encoding/csv"
"encoding/json"
"cloud.google.com/go/firestore"
firebase "firebase.google.com/go"
"github.com/fatih/structs"
//"github.com/gorilla/mux"
//"github.com/rs/cors"
"net/http"
"strings"
//firebase "firebase.google.com/go"
"fmt"
"log"
"firebase.google.com/go/auth"
"google.golang.org/api/iterator"
"google.golang.org/api/option"
//"net/http"
"os"
"strconv"
"sync"
"time"
)
var ch chan User
var client *auth.Client
var dbClient *firestore.Client
var waitGroup sync.WaitGroup
var projectId string
type User struct {
PaychexId string
FirstName string
LastName string
MiddleInitial string
Email string
CellPhone string
HomePhone string
WorkPhone string
FaxNumber string
SSN string
DOB *time.Time
Address string
Address2 string
City string
State string
Zip int
Status bool
HireDate *time.Time
TerminationDate *time.Time
BaseRate float64
}
type Shift struct {
clientUid string
clientName string
aideUid string
status string
startTime *time.Time
endTime *time.Time
}
type BillingUser struct {
PaychexId string
FirstName string
LastName string
AuthorizedHours float32
BaseRate float64
TotalHours float32
}
type HHAShift struct {
AgencyTaxID string
PayerID string
MedicaidNumber string
CaregiverCode string
FirstName string
LastName string
Gender string
DOB string
SSN string
ScheduleID string
ProcedureCode string
ScheduleStart string
ScheduleEnd string
VisitStart string
VisitEnd string
EVVStart string
EVVEnd string
ServiceLocation string
Duties string
ClockInPhoneNumber string
ClockInLong string
ClockInLat string
ClockInEVVOtherInfo string
ClockOutPhoneNumber string
ClockOutLong string
ClockOutLat string
ClockOutEVVOtherInfo string
InvoiceNumber string
VisitEditReasonCode string
VisitEditActionTaken string
Notes string
IsDeletion string
InvoiceLineItemID string
MissedVisit string
MissedVisitReasonCode string
MissedVisitActionTakenCode string
TimesheetReqired string
TimesheetApproved string
UserField1 string
UserField2 string
UserField3 string
UserField4 string
UserField5 string
}
type Client struct {
PayorId string
ClientId string
FirstName string
LastName string
AuthorizedHours float64
DOB time.Time
Address string
City string
State string
Zip int
PhoneNumber string
}
func parseCsv(csvFile string) {
file, _ := os.Open(csvFile)
reader := csv.NewReader(bufio.NewReader(file))
lines, err := reader.ReadAll()
if err != nil {
log.Fatalf("error reading all lines: %v", err)
}
for i, line := range lines {
if i == 0 {
// skip header line
continue
}
stringi := strconv.Itoa(i)
email := stringi + "@moraviahealth.com"
user := User{
PaychexId: line[0],
FirstName: line[1],
LastName: line[2],
Email: email,
}
ch <- user
}
}
type test struct {
StartTime string `json:"startDate"`
EndTime string `json:"endDate"`
}
func createHHAExchangeCSV(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
var t test
err := decoder.Decode(&t)
if err != nil {
panic(err)
}
StartTime, err := time.Parse("2006-01-02", t.StartTime)
if err != nil {
fmt.Println(err)
}
EndTime, err := time.Parse("2006-01-02", t.EndTime)
if err != nil {
fmt.Println(err)
}
fmt.Println("here")
client, err := firestore.NewClient(context.Background(), projectId)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
var HHAShifts []HHAShift
shifts := client.Collection("Shifts").Where("startTime", ">=", StartTime).Where("startTime", "<=", EndTime).Where("status", "==", "approved").Documents(context.Background())
for {
doc, err := shifts.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to iterate: %v", err)
}
aideUid := fmt.Sprintf("%v", doc.Data()["aideUid"])
clientId := fmt.Sprintf("%v", doc.Data()["clientUid"])
user, _ := client.Collection("users").Doc(aideUid).Get(context.Background())
client, _ := client.Collection("Patients").Doc(clientId).Get(context.Background())
userData := user.Data()
shift := HHAShift{
AgencyTaxID: "273049364", //done
PayerID: fmt.Sprintf("%v", client.Data()["PayorId"]), // need this
MedicaidNumber: "", //done
ScheduleID: doc.Ref.ID,
ProcedureCode: "W1793",
VisitEnd: "", //done
EVVStart: "", //done
EVVEnd: "", //done
ServiceLocation: "Service Location 1", // need this CITY (phl = service location 1, hrs service location 2, pit service location 3)
ClockInEVVOtherInfo: "", // need this What to put?
ClockOutLong: "", // done
ClockOutLat: "", // done
ClockOutEVVOtherInfo: "", //skip
InvoiceNumber: "", // skip
VisitEditReasonCode: "", // need codes
VisitEditActionTaken: "", // need this
Notes: "", // skip
IsDeletion: "", // skip
InvoiceLineItemID: "", // need this
MissedVisit: "", // need this
MissedVisitReasonCode: "", // need this
MissedVisitActionTakenCode: "", // need this
}
shift.FirstName = fmt.Sprintf("%v", userData["FirstName"])
shift.LastName = fmt.Sprintf("%v", userData["LastName"])
shift.CaregiverCode = fmt.Sprintf("%v", doc.Data()["aideUid"])
shift.ScheduleStart = parseDateHHA(fmt.Sprintf("%v", doc.Data()["startTime"]))
shift.ScheduleEnd = parseDateHHA(fmt.Sprintf("%v", doc.Data()["endTime"]))
shift.VisitStart = parseDateHHA(fmt.Sprintf("%v", doc.Data()["startTime"]))
shift.VisitEnd = parseDateHHA(fmt.Sprintf("%v", doc.Data()["endTime"]))
shift.EVVStart = parseDateHHA(fmt.Sprintf("%v", doc.Data()["clockInTime"]))
shift.EVVEnd = parseDateHHA(fmt.Sprintf("%v", doc.Data()["clockOutTime"]))
shift.ClockInLat = strings.FieldsFunc(fmt.Sprintf("%v", doc.Data()["clockInLocation"]), parseGeo)[1]
shift.ClockInLong = strings.FieldsFunc(fmt.Sprintf("%v", doc.Data()["clockInLocation"]), parseGeo)[3]
shift.ClockOutLat = strings.FieldsFunc(fmt.Sprintf("%v", doc.Data()["clockOutLocation"]), parseGeo)[1]
shift.ClockOutLong = strings.FieldsFunc(fmt.Sprintf("%v", doc.Data()["clockOutLocation"]), parseGeo)[3]
shift.MedicaidNumber = fmt.Sprintf("%v", doc.Data()["clientUid"])
HHAShifts = append(HHAShifts, shift)
parseDateHHA(fmt.Sprintf("%v", doc.Data()["startTime"]))
}
b := &bytes.Buffer{} // creates IO Writer
wr := csv.NewWriter(b) // creates a csv writer that uses the io buffer.
for _, line := range HHAShifts {
//userHours := fmt.Sprintf("%2f", line.TotalHours)
//baseRate := fmt.Sprintf("%2f", line.BaseRate)
s := make([]string, 0)
for _, v := range structs.Values(line) {
s = append(s, v.(string))
}
//var user []string = []string{line.PaychexId, line.FirstName, line.LastName, userHours, baseRate}
if err := wr.Write(s); err != nil {
log.Fatalln("error writing line to csv:", err)
}
}
wr.Flush()
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Origin", "*")
//w.Header().Set("Content-Disposition", "attachment;filename=paychex.csv")
w.Write(b.Bytes())
}
func parseGeo(r rune) bool {
return r == ':' || r == ' '
}
func parseDateHHA(s string) string {
location, err := time.LoadLocation("EST")
if err != nil {
fmt.Println(err)
}
parsedDate, err := time.Parse("2006-01-02 15:04:05.9 +0000 MST", s)
if err != nil {
fmt.Printf("Error parsing date: %v\n", err)
}
dateEST := parsedDate.In(location)
return dateEST.Format("2006-01-02 15:04")
}
func verifyToken(r *http.Request) (err error) {
reqToken := r.Header.Get("Authorization")
splitToken := strings.Split(reqToken, "Bearer")
reqToken = splitToken[1]
_, err = client.VerifyIDToken(context.Background(), reqToken)
if err != nil {
return err
}
return nil
}
func createPaychexCSV(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Expose-Headers", "Authorization")
return
}
err := verifyToken(r)
if err != nil {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("Invalid Request"))
return
}
decoder := json.NewDecoder(r.Body)
var t test
err = decoder.Decode(&t)
if err != nil {
panic(err)
}
StartTime, err := time.Parse("2006-01-02", t.StartTime)
if err != nil {
fmt.Println(err)
}
EndTime, err := time.Parse("2006-01-02", t.EndTime)
if err != nil {
fmt.Println(err)
}
hours := make(map[string]*BillingUser)
shifts := dbClient.Collection("Shifts").Where("startTime", ">=", StartTime).Where("startTime", "<=", EndTime).Documents(context.Background())
for {
doc, err := shifts.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Failed to iterate: %v", err)
}
uid := doc.Data()["aideUid"]
str := fmt.Sprintf("%v", uid)
if str == "" {
fmt.Println("Empty UID")
continue
}
if _, ok := hours[str]; ok {
hours[str].TotalHours += 1
} else {
userInfo, err := dbClient.Collection("users").Doc(str).Get(context.Background())
if err != nil {
continue
}
fmt.Println(userInfo.Data())
paychexId := fmt.Sprintf("%v", userInfo.Data()["PaychexId"])
Firstname := fmt.Sprintf("%v", userInfo.Data()["FirstName"])
Lastname := fmt.Sprintf("%v", userInfo.Data()["LastName"])
pay := fmt.Sprintf("%v", userInfo.Data()["BasePay"])
var basepay, _ = strconv.ParseFloat(pay, 64)
hours[str] = &BillingUser{
PaychexId: paychexId,
TotalHours: 1,
FirstName: Firstname,
LastName: Lastname,
BaseRate: basepay,
}
}
}
b := &bytes.Buffer{} // creates IO Writer
wr := csv.NewWriter(b) // creates a csv writer that uses the io buffer.
for _, line := range hours {
userHours := fmt.Sprintf("%2f", line.TotalHours)
baseRate := fmt.Sprintf("%2f", line.BaseRate)
var user []string = []string{line.PaychexId, line.FirstName, line.LastName, userHours, baseRate}
if err := wr.Write(user); err != nil {
log.Fatalln("error writing line to csv:", err)
}
}
wr.Flush()
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Write(b.Bytes())
}
func importShiftsCSV(w http.ResponseWriter, r *http.Request) {
loc, err := time.LoadLocation("America/New_York")
if err != nil {
fmt.Println(err)
}
reader := csv.NewReader(r.Body)
lines, err := reader.ReadAll()
if err != nil {
log.Fatalf("error reading all lines: %v", err)
}
var shifts []Shift
for i, line := range lines {
startDate := time.Date(2020, 03, 15, 00, 00, 0, 0, loc)
if i == 0 || i == 1 {
// skip header line
continue
}
if line[4] == "" {
fmt.Printf(`Missing Email for %v\n`, line[4])
continue
}
startCol := 6
userInfo := dbClient.Collection("users").Where("Email", "==", line[4]).Documents(context.Background())
var aideUid string
for {
doc, err := userInfo.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("Doc Error: %v", err)
}
aideUid = doc.Ref.ID
fmt.Printf("AidUID: %v\n", aideUid)
}
for day := 0; day < 7; day++ {
if day != 0 {
startDate = startDate.Add(time.Hour * 24)
}
fmt.Println("Here")
fmt.Printf("Start Line: %v\n", line[startCol])
if line[startCol] == "" || line[startCol+1] == "" {
startCol = startCol + 2
fmt.Println("Empty")
continue
}
in := splitTime(line[startCol])
out := splitTime(line[startCol+1])
inHours, _ := strconv.Atoi(in[0])
inMins, _ := strconv.Atoi(in[1])
outHours, _ := strconv.Atoi(out[0])
outMins, _ := strconv.Atoi(out[1])
startTime := time.Date(startDate.Year(), startDate.Month(), startDate.Day(), inHours, inMins, 0, 0, startDate.Location())
endTime := time.Date(startDate.Year(), startDate.Month(), startDate.Day(), outHours, outMins, 0, 0, startDate.Location())
startCol = startCol + 2
_ = startTime.Minute() + endTime.Minute()
shifts = append(shifts, Shift{
clientUid: line[1],
clientName: line[2],
aideUid: aideUid,
startTime: &startTime,
endTime: &endTime,
})
}
}
for i := 0; i < len(shifts); i++ {
go importShift(shifts[i])
}
w.Write([]byte("Success"))
}
func splitTime(s string) []string {
myTime := strings.Split(s, ":")
return myTime
}
func importShift(s Shift) {
_, _, err := dbClient.Collection("Shifts").Add(context.Background(), map[string]interface{}{
"aideUid": s.aideUid,
"clientUid": s.clientUid,
"startTime": s.startTime,
"status": "notStarted",
"endTime": s.endTime,
"clientName": s.clientName,
})
if err != nil {
log.Fatalf("Error Importing Shift %v \n", err)
}
}
func importClientsCSV(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions {
fmt.Println("options")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Access-Control-Max-Age", "3600")
w.WriteHeader(http.StatusNoContent)
return
}
// Set CORS headers for the main request.
w.Header().Set("Access-Control-Allow-Origin", "*")
reader := csv.NewReader(r.Body)
lines, err := reader.ReadAll()
if err != nil {
log.Fatalf("error reading all lines: %v", err)
}
var results []Client
for i, line := range lines {
if i == 0 {
// skip header line
continue
}
//dateClean := strings.Replace(line[4], "/", "-", 3)
DOB, err := time.Parse("1/2/2006", line[5])
if err != nil {
fmt.Println(err)
}
authorizedHours, _ := strconv.ParseFloat(line[4], 64)
zip, _ := strconv.Atoi(line[9])
results = append(results, Client{
PayorId: line[0],
ClientId: line[1],
FirstName: line[2],
LastName: line[3],
AuthorizedHours: authorizedHours,
DOB: DOB,
Address: line[6],
City: line[7],
State: line[8],
Zip: zip,
PhoneNumber: line[10],
})
}
if err != nil {
fmt.Errorf("Failed adding client: %v \n", err)
}
for i := 0; i < len(results); i++ {
go importClient(results[i])
}
w.Write([]byte("Success"))
}
func importClient(client Client) {
_, err := dbClient.Collection("Patients").Doc(client.ClientId).Set(context.Background(), client)
if err != nil {
log.Fatalf("Failed adding client: %v", err)
}
}
func createUser(user User) {
displayName := user.FirstName + " " + user.LastName
fmt.Println(displayName)
params := (&auth.UserToCreate{}).
Email(user.Email).
DisplayName(displayName)
//u, err := client.CreateUser(ctx, params)
u, err := client.CreateUser(context.Background(), params)
if err != nil {
//log.Fatalf("error creating user: %v\n", err)
fmt.Println("Failed adding user %v: %v", user.Email, err)
return
}
uid := u.UID
hi, err := dbClient.Collection("users").Doc(uid).Set(context.Background(), user)
if err != nil {
log.Fatalf("Failed adding user data %v: %v", user.Email, err)
return
}
fmt.Printf(`Successfully created user: %v\n`, hi)
}
func deleteUsers(w http.ResponseWriter, r *http.Request) {
// Note, behind the scenes, the Users() iterator will retrive 1000 Users at a time through the API
ctx := context.Background()
iter := client.Users(ctx, "")
for {
user, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
log.Fatalf("error listing users: %s\n", err)
}
log.Printf("read user user: %v\n", user)
}
// Iterating by pages 100 users at a time.
// Note that using both the Next() function on an iterator and the NextPage()
// on a Pager wrapping that same iterator will result in an error.
pager := iterator.NewPager(client.Users(ctx, ""), 100, "")
for {
var users []*auth.ExportedUserRecord
nextPageToken, err := pager.NextPage(&users)
if err != nil {
log.Fatalf("paging error %v\n", err)
}
for _, u := range users {
err := client.DeleteUser(ctx, u.UID)
if err != nil {
log.Fatalf("error deleting user: %v\n", err)
}
log.Printf("Successfully deleted user: %s\n", u.UID)
}
if nextPageToken == "" {
break
}
}
w.Write([]byte("Success"))
}
func importUsers(w http.ResponseWriter, r *http.Request) {
reader := csv.NewReader(r.Body)
lines, err := reader.ReadAll()
if err != nil {
log.Fatalf("error reading all lines: %v", err)
}
var users []User
for i, line := range lines {
if i == 0 {
// skip header line
continue
}
var status bool
if line[17] == "Active" {
status = true
} else {
status = false
}
BaseRate, _ := strconv.ParseFloat(line[4], 32)
zip, _ := strconv.Atoi(line[16])
userData := User{
PaychexId: line[0],
FirstName: line[1],
LastName: line[2],
MiddleInitial: line[3],
Email: strings.TrimSpace(line[5]),
CellPhone: line[6],
HomePhone: line[7],
WorkPhone: line[8],
FaxNumber: line[9],
SSN: line[10],
Address: line[12],
Address2: line[13],
City: line[14],
State: line[15],
Zip: zip,
Status: status,
BaseRate: BaseRate,
}
userData.TerminationDate, _ = convertDate(line[19])
userData.HireDate, _ = convertDate(line[18])
userData.DOB, _ = convertDate(line[11])
users = append(users, userData)
}
for i := 0; i < len(users); i++ {
go createUser(users[i])
}
w.Write([]byte("Success"))
}
func convertDate(dateString string) (date *time.Time, err error) {
if dateString != "" {
Date, err := time.Parse("1/2/2006", dateString)
if err != nil {
fmt.Println(err)
}
return &Date, nil
} else {
return
}
}
func main() {
projectId = "moravia-phone-verification"
ctx := context.Background()
opt := option.WithCredentialsFile("./key.json")
config := &firebase.Config{ProjectID: "moravia-phone-verification"}
app, err := firebase.NewApp(ctx, config, opt)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
dbClient, err = firestore.NewClient(ctx, projectId, opt)
if err != nil {
log.Fatalf("error initializing dbClient: %v\n", err)
}
client, err = app.Auth(ctx)
if err != nil {
log.Fatalf("error initializingc client: %v\n", err)
}
myMux := http.NewServeMux()
myMux.HandleFunc("/", createPaychexCSV)
myMux.HandleFunc("/hha", createHHAExchangeCSV)
myMux.HandleFunc("/clients", importClientsCSV)
myMux.HandleFunc("/aides", importUsers)
myMux.HandleFunc("/deleteusers", deleteUsers)
myMux.HandleFunc("/importshifts", importShiftsCSV)
port := os.Getenv("PORT")
if port == "" {
port = "8081"
}
http.ListenAndServe(fmt.Sprintf(":%s", port), myMux)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment