Skip to content

Instantly share code, notes, and snippets.

@Nearhan
Created June 9, 2018 20:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nearhan/63927a790afdf4ff46351990cc2220d3 to your computer and use it in GitHub Desktop.
Save Nearhan/63927a790afdf4ff46351990cc2220d3 to your computer and use it in GitHub Desktop.
project struct
package project
import (
"encoding/json"
"time"
"github.com/satori/go.uuid"
"gitlab.qntfy.com/qcr/drago/core"
"gitlab.qntfy.com/qcr/drago/networks"
)
// Project struct used by QCR api version 2
type Project struct {
ID uuid.UUID `json:"id"`
Start UnixTime `json:"startTimestamp"`
End *UnixTime `json:"endTimestamp"`
Definitions []Definition `json:"definitions"`
}
// Definition what a definition is
type Definition struct {
ID uuid.UUID `json:"id"`
Content []Field `json:"content"`
Filter []Field `json:"filter"`
Exclude []Field `json:"exclude"`
}
// Field has a category and a list of values
type Field struct {
Category string `json:"category"`
Values []interface{} `json:"values"`
}
// ToRuleAble returns the a category type that knows how to extract rules
func (f *Field) ToRuleAble() (RuleAble, error) {
switch f.Category {
case "keywords":
return NewKeywordCategory(f.Values)
case "hashtags":
return NewHashtagCategory(f.Values)
case "geo":
return NewGeoCategory(f.Values)
case "url":
return NewURLCategory(f.Values)
default:
return nil, ErrNotSupportedContentCategory
}
}
// UnixTime holds TimeStamp as unix time stamp
type UnixTime struct {
time.Time
}
// UnmarshalJSON implements interface
func (t *UnixTime) UnmarshalJSON(data []byte) error {
var i int64
if err := json.Unmarshal(data, &i); err != nil {
return err
}
*t = UnixTime{time.Unix(i, 0)}
return nil
}
// MarshalJSON implements interface
func (t *UnixTime) MarshalJSON() ([]byte, error) {
i := t.Unix()
return json.Marshal(i)
}
// RuleAble used to turn supported categories into rules
type RuleAble interface {
ToRules() (core.ProtoableRules, error)
}
// ConvertToProjectRequest takes a project and turns it into a core.ProjectRequest
func ConvertToProjectRequest(p *Project) (core.ProjectRequest, error) {
var proj core.ProjectRequest
var rules core.ProtoableRules
for _, def := range p.Definitions {
for _, criteria := range def.Content {
t, err := criteria.ToRuleAble()
if err != nil {
return proj, err
}
rs, err := t.ToRules()
if err != nil {
return proj, err
}
rules = append(rules, rs...)
}
}
var dr core.DataRequest
if p.End == nil {
dr = core.NewEndlessDataRequest(p.ID, p.Start.UTC(), rules...)
} else {
dr = core.NewDataRequest(p.ID, p.Start.UTC(), p.End.UTC(), rules...)
}
raw, err := json.Marshal(p)
if err != nil {
return proj, err
}
return core.ProjectRequest{dr, raw}, nil
}
// ConvertFromProjectRequest takes a core.ProjectRequest and creates a Project via json unmarshal
func ConvertFromProjectRequest(pr core.ProjectRequest) (*Project, error) {
var p Project
err := json.Unmarshal(pr.Project, &p)
return &p, err
}
// KeywordCategory keyword specific category
type KeywordCategory struct {
keywords []string
}
// ToRules knows how to turn keywords into core.ProtoableRules
func (k KeywordCategory) ToRules() (core.ProtoableRules, error) {
var rules core.ProtoableRules
for _, w := range k.keywords {
for _, n := range networks.List() {
r, err := core.NewTermRule(n, w)
if err != nil {
return rules, err
}
rules = append(rules, &r)
}
}
return checkRuleDuplication("keywords", rules)
}
// NewKeywordCategory makes a new KeywordCategory, converts inputs
func NewKeywordCategory(words []interface{}) (KeywordCategory, error) {
keywords := []string{}
for _, w := range words {
var s string
var ok bool
if s, ok = w.(string); !ok {
return KeywordCategory{}, NewFieldTypeError("keyword", "string")
}
keywords = append(keywords, s)
}
return KeywordCategory{keywords}, nil
}
// GeoCategory geo specific category
type GeoCategory struct {
geos [][]float64
}
// ToRules knows how to turn float64 into core.ProtoableRules
func (g GeoCategory) ToRules() (core.ProtoableRules, error) {
var rules core.ProtoableRules
for _, geo := range g.geos {
for _, n := range networks.List() {
r, err := core.NewGeoRule(n, geo)
if err != nil {
return rules, err
}
rules = append(rules, &r)
}
}
return checkRuleDuplication("geos", rules)
}
// NewGeoCategory makes a new GeoCategory, converts inputs to []float64
func NewGeoCategory(arrypoints []interface{}) (GeoCategory, error) {
var geos [][]float64
var points []interface{}
var p float64
var ok bool
//extract inner array
for _, ps := range arrypoints {
if points, ok = ps.([]interface{}); !ok {
return GeoCategory{}, NewFieldTypeError("[]geo", "[]float64")
}
geo := []float64{}
for _, point := range points {
if p, ok = point.(float64); !ok {
return GeoCategory{}, NewFieldTypeError("geo", "float64")
}
geo = append(geo, p)
}
geos = append(geos, geo)
}
return GeoCategory{geos}, nil
}
// URLCategory url specific category
type URLCategory struct {
urls []string
}
// ToRules knows how to turn urls into core.ProtoableRules
func (u URLCategory) ToRules() (core.ProtoableRules, error) {
var rules core.ProtoableRules
for _, u := range u.urls {
for _, n := range networks.List() {
r, err := core.NewURLRule(n, u)
if err != nil {
return rules, err
}
rules = append(rules, &r)
}
}
return checkRuleDuplication("url", rules)
}
// NewURLCategory makes a new UrlCategory, converts inputs
func NewURLCategory(urls []interface{}) (URLCategory, error) {
urlz := []string{}
for _, url := range urls {
var u string
var ok bool
if u, ok = url.(string); !ok {
return URLCategory{}, NewFieldTypeError("urls", "string")
}
urlz = append(urlz, u)
}
return URLCategory{urlz}, nil
}
// HashtagCategory hastag specific category
type HashtagCategory struct {
tags []string
}
// ToRules knows how to turn hashtags into core.ProtoableRules
func (h HashtagCategory) ToRules() (core.ProtoableRules, error) {
var rules core.ProtoableRules
for _, ht := range h.tags {
for _, n := range networks.List() {
r, err := core.NewTermRule(n, ht)
if err != nil {
return rules, err
}
rules = append(rules, &r)
}
}
return checkRuleDuplication("hashtag", rules)
}
// NewHashtagCategory makes a new HastagCategory, converts inputs
func NewHashtagCategory(tags []interface{}) (HashtagCategory, error) {
hashtags := []string{}
for _, tag := range tags {
var t string
var ok bool
if t, ok = tag.(string); !ok {
return HashtagCategory{}, NewFieldTypeError("hashtags", "string")
}
hashtags = append(hashtags, t)
}
return HashtagCategory{hashtags}, nil
}
func checkRuleDuplication(category string, rules core.ProtoableRules) (core.ProtoableRules, error) {
if len(rules) != len(rules.IDToRuleMap()) {
return rules, NewFieldDuplicateValueError(category)
}
return rules, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment