コード例 #1
0
ファイル: alerts.go プロジェクト: icza/iczagps
// checkDeviceID checks the specified device ID and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid).
func checkDeviceID(p *page.Params, devIDst string, isCar bool, devices []*ds.Device) (ok bool) {
	var fieldName string
	if isCar {
		fieldName = `<span class="code">Car GPS Device</span>`
	} else {
		fieldName = `<span class="code">Personal Mobile GPS Device</span>`
	}

	if devIDst == "" {
		if !isCar {
			// Personal Mobile device is optional
			return true
		}
		p.ErrorMsg = template.HTML(fieldName + " must be provided! Please select a Device from the list.")
		return false
	}

	var devID int64
	var err error

	if devID, err = strconv.ParseInt(devIDst, 10, 64); err != nil {
		p.ErrorMsg = template.HTML("Invalid " + fieldName + "! Please select a Device from the list.")
		return false
	}

	// Check if device is owned by the user:
	for _, d := range devices {
		if d.KeyID == devID {
			return true
		}
	}

	p.ErrorMsg = "You do not have access to the specified Device! Please select a Device from the list."
	return false
}
コード例 #2
0
ファイル: settings.go プロジェクト: icza/iczagps
// checkMapPrevSize checks the specified Map preview size string and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid or empty).
func checkMapPrevSize(p *page.Params, settingName, mps string) (ok bool) {
	if mps == "" {
		return true
	}

	basemsg := `Invalid <span class="code">` + settingName + `</span>!`

	parts := strings.Split(mps, "x")
	if len(parts) != 2 {
		p.ErrorMsg = template.HTML(basemsg)
		return false
	}

	for i, part := range parts {
		name := []string{"width", "height"}[i]
		num, err := strconv.Atoi(part)
		if err != nil {
			p.ErrorMsg = SExecTempl(basemsg+` Invalid number for {{index . 0}}: <span class="highlight">{{index . 1}}</span>`, []interface{}{name, part})
			return false
		}
		if num < 100 || num > 640 { // 640 is an API limit for free accounts
			p.ErrorMsg = SExecTempl(basemsg+` {{index . 0}} is outside of valid range (100..640): <span class="highlight">{{index . 1}}</span>`, []interface{}{name, part})
			return false
		}
	}

	return true
}
コード例 #3
0
ファイル: devices.go プロジェクト: icza/iczagps
// checkName checks the specified Device name and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid).
func checkName(p *page.Params, name string) (ok bool) {
	switch {
	case len(name) == 0:
		p.ErrorMsg = template.HTML(`<span class="code">Name</span> must be specified!`)
		return false
	case len(name) > 500:
		p.ErrorMsg = template.HTML(`<span class="code">Name</span> is too long! (cannot be longer than 500 characters)`)
		return false
	}

	return true
}
コード例 #4
0
ファイル: devices.go プロジェクト: icza/iczagps
// checkLogsRetention checks the specified logs retention and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid).
func checkLogsRetention(p *page.Params, logsRetention string) (ok bool) {
	basemsg := `Invalid <span class="code">Logs Retention</span>!`

	num, err := strconv.Atoi(logsRetention)
	if err != nil {
		p.ErrorMsg = template.HTML(basemsg)
		return false
	}
	if num < 0 || num > 9999 {
		p.ErrorMsg = SExecTempl(basemsg+` Value is outside of valid range (0..9,999): <span class="highlight">{{.}}</span>`, num)
		return false
	}

	return true
}
コード例 #5
0
ファイル: common.go プロジェクト: icza/iczagps
// checkContactEmail checks the specified Contact Email and sets an appropriate erorr message
// if there's something wrong with it.
// Returns true if email is acceptable (valid or empty).
func checkContactEmail(p *page.Params, email string) (ok bool) {
	if email == "" {
		return true
	}
	if len(email) > 500 {
		p.ErrorMsg = template.HTML(`<span class="code">Contact email</span> is too long! (cannot be longer than 500 characters)`)
		return false
	}

	if _, err := mail.ParseAddressList(email); err != nil {
		p.ErrorMsg = template.HTML(`Invalid <span class="code">Contact email</span>!`)
		return false
	}
	return true
}
コード例 #6
0
ファイル: register.go プロジェクト: icza/iczagps
// checkAcceptTermsAndPolicy checks the specified accept terms and policty response and sets an appropriate erorr message
// if there's something wrong with it.
// Returns true if it is acceptable (checked).
func checkAcceptTermsAndPolicy(p *page.Params, atap string) (ok bool) {
	if atap == "" {
		p.ErrorMsg = "You must accept the Terms and Policy!"
		return false
	}
	return true
}
コード例 #7
0
ファイル: settings.go プロジェクト: icza/iczagps
// checkMobPageWidth checks the specified Mobile Page width string and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid or empty).
func checkMobPageWidth(p *page.Params, mpw string) (ok bool) {
	if mpw == "" {
		return true
	}

	basemsg := `Invalid <span class="code">Mobile Page width</span>!`

	num, err := strconv.Atoi(mpw)
	if err != nil {
		p.ErrorMsg = SExecTempl(basemsg+` Invalid number: <span class="highlight">{{.}}</span>`, mpw)
		return false
	}
	if num < 400 || num > 10000 {
		p.ErrorMsg = SExecTempl(basemsg+` Value is outside of valid range (400..10000): <span class="highlight">{{.}}</span>`, num)
		return false
	}

	return true
}
コード例 #8
0
ファイル: settings.go プロジェクト: icza/iczagps
// checkLogsPageSize checks the specified Logs Page Size string and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid or empty).
func checkLogsPageSize(p *page.Params, lps string) (ok bool) {
	if lps == "" {
		return true
	}

	basemsg := `Invalid <span class="code">Logs Table Page Size</span>!`

	num, err := strconv.Atoi(lps)
	if err != nil {
		p.ErrorMsg = SExecTempl(basemsg+` Invalid number: <span class="highlight">{{.}}</span>`, lps)
		return false
	}
	if num < 5 || num > 30 {
		p.ErrorMsg = SExecTempl(basemsg+` Value is outside of valid range (5..30): <span class="highlight">{{.}}</span>`, num)
		return false
	}

	return true
}
コード例 #9
0
ファイル: devices.go プロジェクト: icza/iczagps
// checkSearchPrecision checks the specified search precision and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid).
func checkSearchPrecision(p *page.Params, searchPrecision string) (ok bool) {
	basemsg := `Invalid <span class="code">Search Precision</span>!`

	num, err := strconv.ParseInt(searchPrecision, 10, 64)
	if err != nil {
		p.ErrorMsg = template.HTML(basemsg)
		return false
	}
	if num < 0 || num > 1000*1000 {
		p.ErrorMsg = SExecTempl(basemsg+` Value is outside of valid range (0..1,000,000): <span class="highlight">{{.}}</span>`, num)
		return false
	}
	if num%100 != 0 {
		p.ErrorMsg = SExecTempl(basemsg+` Value is not a multiple of 100: <span class="highlight">{{.}}</span>`, num)
		return false
	}

	return true
}
コード例 #10
0
ファイル: common.go プロジェクト: icza/iczagps
// checkGoogleAccounts checks if previous and current Google Accounts match and sets an error message
// informing the user that the currently logged in Google Account has changed.
// Returns true if Google Accounts match.
func checkGoogleAccounts(p *page.Params, googleAccount string) (ok bool) {
	if googleAccount == p.User.Email {
		return true
	}

	const msg = `The current logged in user <span class="highlight">{{.User}}</span> does not match the <span class="code">Google Account</span>.<br/>
This is most likely due to you switched Google Accounts.<br/>
Click here to reload the {{.Page.Link}} page.`

	p.ErrorMsg = SExecTempl(msg, p)
	return false
}
コード例 #11
0
ファイル: settings.go プロジェクト: icza/iczagps
// checkLocationName checks the specified Location name and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid or empty).
func checkLocationName(p *page.Params, locnam string) (ok bool) {
	if locnam == "" {
		return true
	}

	_, err := time.LoadLocation(locnam)
	if err != nil {
		p.ErrorMsg = template.HTML(`Invalid <span class="code">Location name</span>!`)
		return false
	}

	return true
}
コード例 #12
0
ファイル: settings.go プロジェクト: icza/iczagps
// checkMobMapImgFormat checks the specified Mobile Map image format and sets an appropriate error message
// if there's something wrong with it.
// Returns true if is acceptable (valid or empty).
func checkMobMapImgFormat(p *page.Params, imgFormat string) (ok bool) {
	if imgFormat == "" {
		return true
	}

	for _, v := range imgFormats {
		if v == imgFormat {
			return true
		}
	}

	p.ErrorMsg = template.HTML(`Invalid <span class="code">Mobile Map image format</span>!`)

	return false
}
コード例 #13
0
ファイル: logs.go プロジェクト: icza/iczagps
// logs is the logic implementation of the Logs page.
func logs(p *page.Params) {
	c := p.AppCtx

	// First get devices
	var devices []*ds.Device
	if devices, p.Err = cache.GetDevListForAccKey(c, p.Account.GetKey(c)); p.Err != nil {
		return
	}
	p.Custom["Devices"] = devices

	fv := p.Request.FormValue

	p.Custom["Before"] = fv("before")
	p.Custom["After"] = fv("after")
	p.Custom["SearchLoc"] = fv("loc")

	if fv("devID") == "" {
		// No device chosen yet
		return
	}

	var err error

	var devID int64
	if devID, err = strconv.ParseInt(string(fv("devID")), 10, 64); err != nil {
		p.ErrorMsg = "Invalid Device! Please select a Device from the list below."
		return
	}
	// Check if device is owned by the user:
	var dev *ds.Device
	for _, d := range devices {
		if d.KeyID == devID {
			dev = d
			p.Custom["Device"] = d
			break
		}
	}

	if dev == nil {
		p.ErrorMsg = "You do not have access to the specified Device! Please select a Device from the list below."
		return
	}

	// Parse filters:
	var before time.Time
	if fv("before") != "" {
		if before, err = p.ParseTime(timeLayout, strings.TrimSpace(fv("before"))); err != nil {
			p.ErrorMsg = template.HTML(`Invalid <span class="highlight">Before</span>!`)
			return
		}
		// Add 1 second to the parsed time because fraction of a second is not parsed but exists,
		// so this new time will also include records which has the same time up to the second part and has millisecond part too.
		before = before.Add(time.Second)
	}
	var after time.Time
	if fv("after") != "" {
		if after, err = p.ParseTime(timeLayout, strings.TrimSpace(fv("after"))); err != nil {
			p.ErrorMsg = template.HTML(`Invalid <span class="highlight">After</span>!`)
			return
		}
	}
	var searchLoc appengine.GeoPoint
	areaCode := int64(-1)
	if dev.Indexed() && fv("loc") != "" {
		// GPS coordinates; lat must be in range -90..90, lng must be in range -180..180
		baseErr := template.HTML(`Invalid <span class="highlight">Location</span>!`)

		var coords = strings.Split(strings.TrimSpace(fv("loc")), ",")
		if len(coords) != 2 {
			p.ErrorMsg = baseErr
			return
		}
		searchLoc.Lat, err = strconv.ParseFloat(coords[0], 64)
		if err != nil {
			p.ErrorMsg = baseErr
			return
		}
		searchLoc.Lng, err = strconv.ParseFloat(coords[1], 64)
		if err != nil {
			p.ErrorMsg = baseErr
			return
		}
		if !searchLoc.Valid() {
			p.ErrorMsg = template.HTML(`Invalid <span class="highlight">Location</span> specified by latitude and longitude! Valid range: [-90, 90] latitude and [-180, 180] longitude`)
			return
		}
		areaCode = AreaCodeForGeoPt(dev.AreaSize, searchLoc.Lat, searchLoc.Lng)
	}
	var page int

	cursorsString := fv("cursors")
	var cursors = strings.Split(cursorsString, ";")[1:] // Split always returns at least 1 element (and we use semicolon separator before cursors)

	// Form values
	if fv("page") == "" {
		page = 1
	} else {
		page, err = strconv.Atoi(fv("page"))
		if err != nil || page < 1 {
			page = 1
		}
		if page > len(cursors) { // If page is provided, so are (should be) the cursors
			page = len(cursors)
		}
	}

	switch {
	case fv("submitFirstPage") != "":
		page = 1
	case fv("submitPrevPage") != "":
		if page > 1 {
			page--
		}
	case fv("submitNextPage") != "":
		page++
	}

	pageSize := p.Account.GetLogsPageSize()

	if ps := fv("pageSize"); ps != "" && ps != strconv.Itoa(pageSize) {
		// Page size has been changed (on Settings page), drop cursors, render page 1
		page = 1
		cursorsString = ""
		cursors = make([]string, 0, 1)
	}

	// 'ts all good, proceed with the query:
	q := datastore.NewQuery(ds.ENameGPS).Filter(ds.PNameDevKeyID+"=", devID)
	if !before.IsZero() {
		q = q.Filter(ds.PNameCreated+"<", before)
	}
	if !after.IsZero() {
		q = q.Filter(ds.PNameCreated+">", after)
	}
	if areaCode >= 0 {
		q = q.Filter(ds.PNameAreaCodes+"=", areaCode)
	}
	q = q.Order("-" + ds.PNameCreated).Limit(pageSize)

	var records = make([]*ds.GPS, 0, pageSize)

	// If there is a cursor, set it.
	// Page - cursor index mapping:     cursors[page-2]
	//     1st page: no cursor, 2nd page: cursors[0], 3nd page: cursors[1], ...
	if page > 1 && page <= len(cursors)+1 {
		var cursor datastore.Cursor
		if cursor, p.Err = datastore.DecodeCursor(cursors[page-2]); p.Err != nil {
			return
		}
		q = q.Start(cursor)
	}

	// Iterate over the results:
	t := q.Run(c)
	for {
		r := new(ds.GPS)
		_, err := t.Next(r)
		if err == datastore.Done {
			break
		}
		if err != nil {
			// Datastore error
			p.Err = err
			return
		}
		records = append(records, r)
		r.Dd = -1 // For now, will be set if applicable
		if r.Track() {
			// Check the previous (in time) record and calculate distance.
			// If previous is not a Track, check the one before that etc.
			for i := len(records) - 2; i >= 0; i-- {
				if prev := records[i]; prev.Track() {
					prev.Dd = Distance(r.GeoPoint.Lat, r.GeoPoint.Lng, prev.GeoPoint.Lat, prev.GeoPoint.Lng)
					prev.Dt = prev.Created.Sub(r.Created)
					break
				}
			}
		}
	}

	if len(records) == 0 {
		// End of list reached, disable Next page button:
		p.Custom["EndOfList"] = true
	}

	if page == 1 || page > len(cursors) {
		// Get updated cursor and store it for next page:
		var cursor datastore.Cursor
		if cursor, p.Err = t.Cursor(); p.Err != nil {
			return
		}
		cursorString := cursor.String()
		if page == 1 {
			// If new records were inserted, they appear on the first page in which case
			// the cursor for the 2nd page changes (and all other cursors will change).
			// In this case drop all the cursors:
			if len(cursors) > 0 && cursors[0] != cursorString {
				cursorsString = ""
				cursors = make([]string, 0, 1)
			}
		} else {
			// When end of list is reached, the same cursor will be returned
			if len(records) == 0 && page == len(cursors)+1 && cursors[page-2] == cursorString {
				// Add 1 extra, empty page, but not more.
				if page > 2 && cursors[page-3] == cursorString {
					// An extra, empty page has already been added, do not add more:
					page--
				}
			}
		}

		if page > len(cursors) {
			cursors = append(cursors, cursorString)
			cursorsString += ";" + cursorString
		}
	}

	// Calculate labels: '1'..'9' then 'A'...
	for i, lbl := len(records)-1, '1'; i >= 0; i-- {
		if r := records[i]; r.Track() {
			r.Label = lbl
			if lbl == '9' {
				lbl = 'A' - 1
			}
			lbl++
		}
	}

	p.Custom["CursorList"] = cursors
	p.Custom["Cursors"] = cursorsString

	p.Custom["Page"] = page
	p.Custom["PageSize"] = pageSize
	p.Custom["RecordOffset"] = (page-1)*pageSize + 1
	p.Custom["Records"] = records
	if p.Mobile {
		p.Custom["MapWidth"], p.Custom["MapHeight"] = p.Account.GetMobMapPrevSize()
		p.Custom["MapImgFormat"] = p.Account.GetMobMapImgFormat()
	} else {
		p.Custom["MapWidth"], p.Custom["MapHeight"] = p.Account.GetMapPrevSize()
	}
	p.Custom["APIKey"] = "AIzaSyCEU_tZ1n0-mMg4woGKIfPqdbi0leSKvjg"
	p.Custom["AllMarkers"] = allMarkers(records)

	if len(records) == 0 {
		if page == 1 {
			if before.IsZero() && after.IsZero() && areaCode < 0 {
				p.Custom["PrintNoRecordsForDev"] = true
			} else {
				p.Custom["PrintNoMatchForFilters"] = true
			}
		} else {
			p.Custom["PrintNoMoreRecords"] = true
		}
	}
}
コード例 #14
0
ファイル: devices.go プロジェクト: icza/iczagps
// devices is the logic implementation of the Devices page.
func devices(p *page.Params) {
	c := p.AppCtx
	fv := p.Request.PostFormValue

	// Initial values:
	p.Custom["SearchPrecision"] = 1000
	p.Custom["LogsRetention"] = 60

	// Detect form submits:
	switch {
	case fv("submitAdd") != "":
		// Add New Device form submitted!
		// Checks:
		switch {
		case !checkName(p, fv("name")):
		case !checkSearchPrecision(p, fv("searchPrecision")):
		case !checkLogsRetention(p, fv("logsRetention")):
		}
		if p.ErrorMsg == nil {
			// All data OK, save new Device
			searchPrecision, _ := strconv.ParseInt(fv("searchPrecision"), 10, 64)
			logsRetention, _ := strconv.Atoi(fv("logsRetention"))
			dev := ds.Device{fv("name"), 0, logsRetention, "", time.Now(), 0}
			dev.SetSearchPrecision(searchPrecision)
			genNewRandID(p, &dev)
			if p.Err != nil {
				return
			}
			if _, p.Err = datastore.Put(c, datastore.NewIncompleteKey(c, ds.ENameDevice, p.Account.GetKey(c)), &dev); p.Err != nil {
				return // Datastore error
			}
			p.InfoMsg = "New Device saved successfully."
			// Clear from memcache:
			cache.ClearDevListForAccKey(c, p.Account.GetKey(c))
		} else {
			// Submitted values
			p.Custom["Name"] = fv("name")
			p.Custom["SearchPrecision"] = fv("searchPrecision")
			p.Custom["LogsRetention"] = fv("logsRetention")
		}
	case fv("submitRename") != "":
		// Rename Device form submitted!
		if !checkName(p, fv("name")) {
			break
		}
		if devID, err := strconv.ParseInt(string(fv("devID")), 10, 64); err != nil {
			p.ErrorMsg = "Invalid Device!"
		} else {
			devKey := datastore.NewKey(c, ds.ENameDevice, "", devID, p.Account.GetKey(c))
			var dev ds.Device
			if err = datastore.Get(c, devKey, &dev); err != nil {
				if err == datastore.ErrNoSuchEntity {
					p.ErrorMsg = "You do not have access to the specified Device!"
				} else {
					// Real datastore error
					p.Err = err
					return
				}
			} else {
				// Proceed to rename
				dev.Name = fv("name")
				if _, p.Err = datastore.Put(c, devKey, &dev); p.Err != nil {
					return // Datastore error
				}
				p.InfoMsg = "Device renamed successfully."
				// Clear from memcache:
				cache.ClearDevListForAccKey(c, p.Account.GetKey(c))
				cache.ClearDeviceForRandID(c, dev.RandID)
				dev.KeyID = devID // This is important (device is loaded freshly and not yet set)!
				cache.CacheDevice(c, &dev)
			}
		}
	case fv("submitGenNewKey") != "":
		// Generate New Key form submitted!
		if devID, err := strconv.ParseInt(string(fv("devID")), 10, 64); err != nil {
			p.ErrorMsg = "Invalid Device!"
		} else {
			devKey := datastore.NewKey(c, ds.ENameDevice, "", devID, p.Account.GetKey(c))
			var dev ds.Device
			if err = datastore.Get(c, devKey, &dev); err != nil {
				if err == datastore.ErrNoSuchEntity {
					p.ErrorMsg = "You do not have access to the specified Device!"
				} else {
					// Real datastore error
					p.Err = err
					return
				}
			} else {
				// Proceed to generate new key
				// Store old RandID to remove it from cache if saving succeeds
				oldRandID := dev.RandID
				genNewRandID(p, &dev)
				if p.Err != nil {
					return
				}
				if _, p.Err = datastore.Put(c, devKey, &dev); p.Err != nil {
					return // Datastore error
				}
				p.InfoMsg = template.HTML("New Key generated successfully.")
				p.ImportantMsg = template.HTML("<b>Important!</b> You have to update the URL in the client application else further GPS tracking calls will be discarded!")
				cache.ClearDeviceForRandID(c, oldRandID)
				dev.KeyID = devID // This is important (device is loaded freshly and not yet set)!
				cache.CacheDevice(c, &dev)
			}
		}
	}

	q := datastore.NewQuery(ds.ENameDevice).Ancestor(p.Account.GetKey(c)).Order(ds.PNameName)

	var devices []*ds.Device
	var devKeys []*datastore.Key
	if devKeys, p.Err = q.GetAll(c, &devices); p.Err != nil {
		return
	}
	for i := range devices {
		devices[i].KeyID = devKeys[i].IntID()
	}

	p.Custom["Devices"] = devices
}
コード例 #15
0
ファイル: register.go プロジェクト: icza/iczagps
// register is the logic implementation of the Register page.
func register(p *page.Params) {
	// Register page is special. Unlike with other pages we do have to check User and Account here
	// Because even though Register page works with User, logged in user is not required for this page!

	// User might have logged out on a separate tab
	if p.User == nil {
		return
	}
	// User might have registered on a different tab
	if p.Account != nil {
		return
	}

	fv := p.Request.PostFormValue

	if fv("submitRegister") == "" {
		// No form submitted. Initial values:
		p.Custom["GoogleAccount"] = p.User.Email
		return
	}

	p.Custom["GoogleAccount"] = fv("googleAccount")
	p.Custom["ContactEmail"] = fv("contactEmail")
	p.Custom["AcceptTermsAndPolicy"] = fv("acceptTermsAndPolicy")

	// Checks:
	switch {
	case !checkGoogleAccounts(p, fv("googleAccount")):
	case !checkContactEmail(p, fv("contactEmail")):
	case !checkAcceptTermsAndPolicy(p, fv("acceptTermsAndPolicy")):
	}

	// UNTIL PROJECT GOES PUBLIC, DISABLE REGISTRATION:
	if !appengine.IsDevAppServer() && p.ErrorMsg == nil {
		p.ErrorMsg = "REGISTRATION IS CURRENTLY DISABLED! Contact the administrator if you would like to register!"
		return
	}
	// END OF: UNTIL PROJECT GOES PUBLIC, DISABLE REGISTRATION

	if p.ErrorMsg != nil {
		return
	}

	// All data OK, save new Account
	c := p.AppCtx
	acc := ds.Account{Email: p.User.Email, Lemail: strings.ToLower(p.User.Email), UserID: p.User.ID, ContactEmail: fv("contactEmail"), Created: time.Now()}
	var key *datastore.Key
	if key, p.Err = datastore.Put(c, datastore.NewIncompleteKey(c, ds.ENameAccount, nil), &acc); p.Err == nil {
		p.Custom["Created"] = true
		acc.KeyID = key.IntID()
		p.Account = &acc
		// Put new Account into the cache
		cache.CacheAccount(c, p.Account)
	}

	// Send registration email (Account info email)
	const adminEmail = "Andras Belicza <*****@*****.**>"
	msg := &mail.Message{
		Sender:  adminEmail,
		To:      []string{acc.Email},
		Bcc:     []string{adminEmail},
		ReplyTo: adminEmail,
		Subject: "[IczaGPS] Account Info",
		Body:    fmt.Sprintf(accountInfoMail, acc.Email),
	}
	if len(acc.ContactEmail) > 0 {
		msg.Cc = []string{acc.ContactEmail}
	}
	if err := mail.Send(c, msg); err == nil {
		c.Infof("Sent successful registration email.")
	} else {
		c.Errorf("Couldn't send email: %v", err)
	}
}
コード例 #16
0
ファイル: alerts.go プロジェクト: icza/iczagps
// alerts is the logic implementation of the Alerts page.
func alerts(p *page.Params) {
	c := p.AppCtx

	// First get devices
	var devices []*ds.Device
	if devices, p.Err = cache.GetDevListForAccKey(c, p.Account.GetKey(c)); p.Err != nil {
		return
	}
	p.Custom["Devices"] = devices

	fv := p.Request.PostFormValue

	// Detect form submits:
	switch {
	case fv("submitAdd") != "":
		// Add New Alert form submitted!
		// Checks:
		switch {
		case !checkDeviceID(p, fv("carDeviceID"), true, devices):
		case !checkDeviceID(p, fv("persMobDeviceID"), false, devices):
		}
		if p.ErrorMsg == nil {
			// So far so good. Futher checks: car and personal mobile device must differ
			carDevID, _ := strconv.ParseInt(fv("carDeviceID"), 10, 64)
			var persMobDevID int64
			if fv("persMobDeviceID") != "" {
				persMobDevID, _ = strconv.ParseInt(fv("persMobDeviceID"), 10, 64)
				if carDevID == persMobDevID {
					p.ErrorMsg = template.HTML(`<span class="code">Car GPS Device</span> and <span class="code">Personal Mobile GPS Device</span> cannot be the same!`)
				}
			}
			if p.ErrorMsg == nil {
				// So far still good. Furter check: same alert cannot be saved twice
				q := datastore.NewQuery(ds.ENameAlert).Ancestor(p.Account.GetKey(c))
				var alerts []*ds.Alert
				if _, p.Err = q.GetAll(c, &alerts); p.Err != nil {
					return
				}
				for _, alert := range alerts {
					if alert.CarDevID == carDevID && alert.PersMobDevID == persMobDevID {
						p.ErrorMsg = template.HTML(`An Alert with the same <span class="code">Car GPS Device</span> and <span class="code">Personal Mobile GPS Device</span> already exists!`)
					}
				}
			}
			if p.ErrorMsg == nil {
				// All data OK, save new Alert
				alert := ds.Alert{carDevID, persMobDevID, time.Now(), 0, "", ""}
				if _, p.Err = datastore.Put(c, datastore.NewIncompleteKey(c, ds.ENameAlert, p.Account.GetKey(c)), &alert); p.Err != nil {
					return // Datastore error
				}
				p.InfoMsg = "New Alert saved successfully."
			}
		}
	case fv("submitDelete") != "":
		// Delete Alert form submitted!
		if alertID, err := strconv.ParseInt(string(fv("alertID")), 10, 64); err != nil {
			p.ErrorMsg = "Invalid Alert!"
		} else {
			alertKey := datastore.NewKey(c, ds.ENameAlert, "", alertID, p.Account.GetKey(c))
			// Check if
			var alert ds.Alert
			if err = datastore.Get(c, alertKey, &alert); err != nil {
				if err == datastore.ErrNoSuchEntity {
					p.ErrorMsg = "You do not have access to the specified Alert!"
				} else {
					// Real datastore error
					p.Err = err
					return
				}
			} else {
				// Proceed to delete
				if p.Err = datastore.Delete(c, alertKey); p.Err != nil {
					return // Datastore error
				}
				p.InfoMsg = "Alert deleted successfully."
			}
		}
	}

	q := datastore.NewQuery(ds.ENameAlert).Ancestor(p.Account.GetKey(c))

	var alerts []*ds.Alert
	var alertKeys []*datastore.Key
	if alertKeys, p.Err = q.GetAll(c, &alerts); p.Err != nil {
		return
	}
	for i, alert := range alerts {
		alert.KeyID = alertKeys[i].IntID()
		for _, d := range devices {
			switch d.KeyID {
			case alert.CarDevID:
				alert.CarDevName = d.Name
			case alert.PersMobDevID:
				alert.PersMobDevName = d.Name
			}
		}
	}

	p.Custom["Alerts"] = alerts
}