Skip to content

Commit

Permalink
Merge branch 'add-whois'
Browse files Browse the repository at this point in the history
  • Loading branch information
brimstone committed Jun 13, 2016
2 parents 575d9de + 0a9e811 commit bbf99d0
Show file tree
Hide file tree
Showing 13 changed files with 582 additions and 173 deletions.
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,22 @@ UI:
- `/about` Explains more about how this service works
- `/{{domain}}` Shows report for last checks against domain or status that verification is pending
- `/{{domain}}/{{verificationHash}}` Shows details about checks, lets user cancel service
- `/{{domain}}/{{verificationHash}}/cancel` Terminates service

API:
- `/{{domain}}.json` Gets status of checks as json
- `/{{domain}}/{{verificationHash}}.json` Shows details about checks as json
- POST `/` Sets up domain to be checked.
- domain={{domain}}
- GET `/{{domain}}` Gets status of checks as json
- `checking`: true or false.
- true: The system is checking attributes of the domain
- false: The system is not keeping an eye on the domain. Check on `cooldowntime`
- `cooldowntime`: Time of when the system will start checking the domain again.
- `email`: Email address alerts are sent
- `updated`: Time of last check of any type.
- GET `/{{domain}}/{{verificationHash}}` Shows details about checks as json.
- Same as the `/{{domain}}` checks above, including:
- `checks`: Array of checks.
- `updated`: Time when the check was last performed.
- `name`: Name of check.
- `value`: Value of the check the system is watching to change.
- POST `/{{domain}}/{{verificationHash}}/cancel` Terminates service.
- confirm=true
139 changes: 139 additions & 0 deletions analyticsemail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package main

import (
"bytes"
"fmt"
"html/template"
"log"
"strconv"

beegoorm "github.com/astaxie/beego/orm"
)

// AnalyticURL Counts of urls
type AnalyticURL struct {
Count int
URL string
HTTPCode int
}

// AnalyticIP Counts of IPs
type AnalyticIP struct {
Count int
IP string
}

// AnalyticReferer Counts of Referers
type AnalyticReferer struct {
Count int
Referer string
}

// AnalyticsEmails Job Specific Functions
type AnalyticsEmails struct {
// filtered
WeeklyNot200 []AnalyticURL
WeeklyIP []AnalyticIP
WeeklyReferer []AnalyticReferer
}

// Run will get triggered automatically.
func (e AnalyticsEmails) Run() {
var err error
var msgText bytes.Buffer
var msgHTML bytes.Buffer
// Queries the DB
// Sends some email
fmt.Println("Nightly Analytic email")

// Non 200s
var results []beegoorm.Params
_, err = orm.Raw(`select count(url) as count, url, httpcode
from client_request
where httpcode != 200
group by url
order by count desc;`).Values(&results)
for i := range results {
count, _ := strconv.Atoi(results[i]["count"].(string))
httpcode, _ := strconv.Atoi(results[i]["httpcode"].(string))
stat := &AnalyticURL{Count: count,
URL: results[i]["url"].(string),
HTTPCode: httpcode,
}
e.WeeklyNot200 = append(e.WeeklyNot200, *stat)
}

// IPs
_, err = orm.Raw(`select count(ip) as count, ip
from client_request
group by ip
order by count desc`).Values(&results)
for i := range results {
count, _ := strconv.Atoi(results[i]["count"].(string))
stat := &AnalyticIP{Count: count,
IP: results[i]["ip"].(string),
}
e.WeeklyIP = append(e.WeeklyIP, *stat)
}

// referers
_, err = orm.Raw(`select count(referer) as count, referer
from client_request
group by referer
order by count desc`).Values(&results)
for i := range results {
count, _ := strconv.Atoi(results[i]["count"].(string))
stat := &AnalyticReferer{Count: count,
Referer: results[i]["referer"].(string),
}
e.WeeklyReferer = append(e.WeeklyReferer, *stat)
}

if err != nil {
log.Println("[ERROR] EmailAnalytics Query", err)
return
}

TemplateText, err := template.
New("emailanalytics.txt").
ParseFiles("tmpls/emailanalytics.txt")
if err != nil {
log.Println("[ERROR] EmailAnalytics TemplateText Parse", err)
return
}

TemplateHTML, err := template.
New("emailanalytics.html").
ParseFiles("tmpls/emailanalytics.html")
if err != nil {
log.Println("[ERROR] EmailAnalytics TemplateHTML Parse", err)
return
}

err = TemplateText.Execute(&msgText, e)
if err != nil {
log.Println("[ERROR] EmailAnalytics TemplateText Execute", err)
return
}
err = TemplateHTML.Execute(&msgHTML, e)
if err != nil {
log.Println("[ERROR] EmailAnalytics TemplateHTML Execute", err)
return
}

/*
Debug bits
log.Println(msgHTML.String())
return
*/

err = SendEmail("matt@domain.glass",
"Nightly Analytics",
msgText,
msgHTML,
)
if err != nil {
log.Println("[ERROR] EmailAnalytics", err)
return
}
}
96 changes: 96 additions & 0 deletions checknewdomain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package main

import (
"bytes"
"fmt"
"log"
"math/rand"
"strconv"
"time"

"html/template"

beegoorm "github.com/astaxie/beego/orm"
"github.com/dineshappavoo/basex"
)

type CheckNewDomain struct {
DomainName string
VerificationCode string
}

func (c CheckNewDomain) Run() {
var msgText bytes.Buffer
var msgHTML bytes.Buffer

domain := Domain{OwnerEmail: ""}
err := orm.Read(&domain, "OwnerEmail")
// No results, no log
if err == beegoorm.ErrNoRows {
return
}
if err != nil {
// TODO email me about this
fmt.Println("Error while running CheckNewDomain(Read):", err)
return
}
fmt.Println("Adding", domain.Name)
whois, err := GetWhoisInfo(domain.Name)
if err != nil {
// TODO email me about this
fmt.Println("Error while running CheckNewDomain(whois):", err)
return
}
// Save the url
domain.OwnerEmail = whois.Emails[0]
// Generate a unique validation code

r := rand.New(rand.NewSource(time.Now().UnixNano()))
encoded, _ := basex.Encode(strconv.Itoa(r.Intn(916132832)))
// TODO email me about this
domain.VerificationCode = encoded
_, err = orm.Update(&domain)
if err != nil {
fmt.Println("Error while running CheckNewDomain(Update):", err)
return
}
c.VerificationCode = encoded
c.DomainName = domain.Name

TemplateText, err := template.
New("verificationemail.txt").
ParseFiles("tmpls/verificationemail.txt")
if err != nil {
log.Println("[ERROR] CheckNewDomain TemplateText Parse", err)
return
}

TemplateHTML, err := template.
New("verificationemail.html").
ParseFiles("tmpls/verificationemail.html")
if err != nil {
log.Println("[ERROR] CheckNewDomain TemplateHTML Parse", err)
return
}

err = TemplateText.Execute(&msgText, c)
if err != nil {
log.Println("[ERROR] CheckNewDomain TemplateText Execute", err)
return
}
err = TemplateHTML.Execute(&msgHTML, c)
if err != nil {
log.Println("[ERROR] CheckNewDomain TemplateHTML Execute", err)
return
}

err = SendEmail(domain.OwnerEmail,
"domain.glass Verification Code for "+domain.Name,
msgText,
msgHTML,
)
if err != nil {
log.Println("[ERROR] CheckNewDomain", err)
return
}
}
1 change: 1 addition & 0 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func InitDatabase() error {
beegoorm.RegisterModel(new(ClientRequest))
beegoorm.RegisterModel(new(Domain))
beegoorm.RegisterModel(new(Payment))
beegoorm.RegisterModel(new(WhoisServer))

// connect to our database
if os.Getenv("OPENSHIFT_MYSQL_DB_HOST") != "" {
Expand Down
74 changes: 65 additions & 9 deletions domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,89 @@ package main
import (
"net/http"
"regexp"
"strings"
"time"

"github.com/gin-gonic/contrib/static"
"github.com/gin-gonic/gin"
)

// Domain Handle main route
func apiDomain(c *gin.Context) {
c.JSON(200, gin.H{
"message": "hello",
})
}

// Domain holds information about a domain
type Domain struct {
ID int64 `orm:"pk;auto;column(id)"`
Name string
VerificationCode string
VerificationCode string `orm:"unique"`
OwnerEmail string
Payment *Payment `orm:"rel(fk)"`
Payments []*Payment `orm:"reverse(many)"`
}

// Payment holds payment information
type Payment struct {
ID int64 `orm:"pk;auto;column(id)"`
Timestamp time.Time
Plan string
Domain *Domain `orm:"rel(fk)"`
}

func validDomain(c *gin.Context, domainName string) bool {

matched, _ := regexp.MatchString("^[a-z0-9._]*\\.[a-z]{2,}$", domainName)
if !matched {
c.JSON(400, gin.H{
"error": "Domain " + domainName + " not in a valid format",
})
return false
}
return true
}

// Domain Handle main route
func getDomain(c *gin.Context) {
domainName := strings.ToLower(c.Param("domain"))
if !validDomain(c, domainName) {
return
}
// This should only read from the database
domain := Domain{Name: domainName}
err := orm.Read(&domain, "Name")
// if the domain doesn't exist
if err != nil {
// Let the user know
c.JSON(400, gin.H{
"error": "Domain " + domainName + " does not exist",
})
return
}
/*
whois, _ := GetWhoisInfo(domain)
*/
c.JSON(200, gin.H{
"checking": true, // TODO make this mean something
"cooldowntime": time.Now(), // TODO account for payments, checks, etc
"email": domain.OwnerEmail,
"updated": time.Now(), // TODO make this a max of the checks
})
}

// addDomain
func addDomain(c *gin.Context) {
domainName := strings.ToLower(c.PostForm("domain"))
if !validDomain(c, domainName) {
return
}
domain := Domain{Name: domainName}
_, _, err := orm.ReadOrCreate(&domain, "Name")
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}
c.JSON(200, gin.H{
"status": true,
"message": "Queued for checking",
})

}

func viewdomain(c *gin.Context) {
Expand Down
Loading

0 comments on commit bbf99d0

Please sign in to comment.