Example #1
0
func suggest(c *gin.Context) {

	cfg := getConfig(c)

	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		c.AbortWithError(http.StatusInternalServerError, err)
		return
	}

	for {

		movie, err := cfg.Store.GetRandom()

		if err != nil {
			continue
		}

		if err := conn.WriteJSON(movie); err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}

		time.Sleep(socketWaitFor)
	}

}
Example #2
0
func (pc *NodeController) getNodeAddDOAction(c *gin.Context) {

	a, err := models.AccessMapper.FetchOne("do")
	if err != nil {
		panic(err)
	}

	if a == nil {

		c.HTML(http.StatusOK, "node_add_do.html", map[string]interface{}{})
		return
	}

	oauthClient := oauth2.NewClient(oauth2.NoContext, &DOTokenSource{
		AccessToken: a.AccessKey,
	})
	client := godo.NewClient(oauthClient)

	regions, _, err := client.Regions.List(&godo.ListOptions{})
	if err != nil {
		panic(err)
	}

	sizes, _, err := client.Sizes.List(&godo.ListOptions{})
	if err != nil {
		panic(err)
	}

	c.HTML(http.StatusOK, "node_add_do.html", map[string]interface{}{
		"AccessKey": true,
		"DORegions": regions,
		"DOSizes":   sizes,
	})
}
Example #3
0
func GroupCheck(tc *ginoauth2.TokenContainer, access_tuple []ginoauth2.AccessTuple, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	if err != nil {
		glog.Error("failed to get team info, caused by: ", err)
		return false
	}
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
		return false
	}
	for _, teamInfo := range data {
		for idx := range access_tuple {
			at := access_tuple[idx]
			if teamInfo.Id_name == at.Uid {
				ctx.Set("uid", tc.Scopes["uid"].(string))
				ctx.Set("team", teamInfo.Id_name)
				glog.Infof("Grant access to %s as team member of %s\n", tc.Scopes["uid"].(string), teamInfo.Id_name)
				return true
			}
		}
	}

	return false
}
Example #4
0
func (m *MessagesController) likeOrUnlike(ctx *gin.Context, action string, message models.Message, topic models.Topic, user models.User) {
	isReadAccess := topic.IsUserReadAccess(user)
	if !isReadAccess {
		ctx.AbortWithError(http.StatusInternalServerError, errors.New("No Read Access to topic "+message.Topics[0]))
		return
	}

	info := ""
	if action == "like" {
		err := message.Like(user)
		if err != nil {
			log.Errorf("Error while like a message %s", err)
			ctx.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		info = "like added"
	} else if action == "unlike" {
		err := message.Unlike(user)
		if err != nil {
			log.Errorf("Error while like a message %s", err)
			ctx.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		info = "like removed"
	} else {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid action : " + action)})
		return
	}
	go models.WSMessage(&models.WSMessageJSON{Action: action, Username: user.Username, Message: message})
	ctx.JSON(http.StatusCreated, gin.H{"info": info})
}
Example #5
0
func (m *MessagesController) updateMessage(ctx *gin.Context, messageIn *messageJSON, message models.Message, user models.User, topic models.Topic) {
	info := ""
	if messageIn.Action == "update" {

		if !topic.CanUpdateMsg && !topic.CanUpdateAllMsg {
			ctx.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("You can't update a message on topic %s", topic.Topic)})
			return
		}

		if !topic.CanUpdateAllMsg && message.Author.Username != user.Username {
			ctx.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Could not update a message from another user %s than you %s", message.Author.Username, user.Username)})
			return
		}

		message.Text = messageIn.Text
		err := message.Update(user, topic)
		if err != nil {
			log.Errorf("Error while update a message %s", err)
			ctx.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		info = fmt.Sprintf("Message updated in %s", topic.Topic)
	} else {
		ctx.AbortWithError(http.StatusBadRequest, errors.New("Invalid action : "+messageIn.Action))
		return
	}
	go models.WSMessage(&models.WSMessageJSON{Action: messageIn.Action, Username: user.Username, Message: message})
	out := &messageJSONOut{Message: message, Info: info}
	ctx.JSON(http.StatusOK, out)
}
Example #6
0
func ArticlesDetail(c *gin.Context) {
	article_id := c.Params.ByName("id")
	a_id, _ := strconv.Atoi(article_id)
	article := getArticle(a_id)
	content := gin.H{"title": article.Title, "content": article.Content}
	c.JSON(200, content)
}
Example #7
0
func HandleQuery(query string, c *gin.Context) {
	rawQuery, err := base64.StdEncoding.DecodeString(query)
	if err == nil {
		query = string(rawQuery)
	}

	result, err := DB(c).Query(query)
	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	format := getQueryParam(c, "format")
	filename := getQueryParam(c, "filename")

	if filename == "" {
		filename = fmt.Sprintf("pgweb-%v.%v", time.Now().Unix(), format)
	}

	if format != "" {
		c.Writer.Header().Set("Content-disposition", "attachment;filename="+filename)
	}

	switch format {
	case "csv":
		c.Data(200, "text/csv", result.CSV())
	case "json":
		c.Data(200, "applicaiton/json", result.JSON())
	case "xml":
		c.XML(200, result)
	default:
		c.JSON(200, result)
	}
}
Example #8
0
func ShowRepo(c *gin.Context) {
	user := session.User(c)
	repo := session.Repo(c)

	builds, _ := store.GetBuildList(c, repo)
	groups := []*model.BuildGroup{}

	var curr *model.BuildGroup
	for _, build := range builds {
		date := time.Unix(build.Created, 0).Format("Jan 2 2006")
		if curr == nil || curr.Date != date {
			curr = &model.BuildGroup{}
			curr.Date = date
			groups = append(groups, curr)
		}
		curr.Builds = append(curr.Builds, build)
	}

	httputil.SetCookie(c.Writer, c.Request, "user_last", repo.FullName)

	c.HTML(200, "repo.html", gin.H{
		"User":   user,
		"Repo":   repo,
		"Builds": builds,
		"Groups": groups,
	})

}
Example #9
0
func FromContext(c *gin.Context) *Session {
	if val, ok := c.Get("session"); ok {
		if s, ok := val.(*Session); ok {
			return s
		}
	}

	cookie, err := c.Request.Cookie(CookieKey)
	if err != nil {
		s := Create()
		s.storeInContext(c)
		http.SetCookie(c.Writer, s.cookie())
		return s
	}

	s, err := Load(cookie.Value)
	if err != nil {
		s := Create()
		s.storeInContext(c)
		http.SetCookie(c.Writer, s.cookie())
		return s
	}

	s.storeInContext(c)
	return s
}
Example #10
0
File: file.go Project: tka/goyangi
// CreateFiles creates files.
func CreateFiles(c *gin.Context) (int, error) {
	var forms FilesForm
	start := time.Now()
	c.BindWith(&forms, binding.JSON)
	log.Debugf("CreateFiles c form : %v", forms)

	user, _ := userService.CurrentUser(c)
	sqlStrBuffer := new(bytes.Buffer)
	stringHelper.Concat(sqlStrBuffer, "INSERT INTO file(user_id, name, size, created_at) VALUES ")
	values := []interface{}{}
	for _, file := range forms.Files {
		stringHelper.Concat(sqlStrBuffer, "(?, ?, ?, ?),")
		values = append(values, user.Id, file.Name, file.Size, time.Now())

	}
	// sqlStrBuffer.Truncate(sqlStrBuffer.Len() - 1) is slower than slice.
	if len(values) > 0 {
		sqlStr := sqlStrBuffer.String()
		sqlStr = sqlStr[0 : len(sqlStr)-1]
		log.Debugf("sqlStr for File : %s", sqlStr)
		db.ORM.Exec(sqlStr, values...)
		elapsed := time.Since(start)
		log.Debugf("CreateFiles elapsed : %s", elapsed)
	}

	return http.StatusCreated, nil
}
Example #11
0
func usersDetail(c *gin.Context) {
	user_id := c.Params.ByName("id")
	a_id, _ := strconv.Atoi(user_id)
	user := getuser(a_id)
	content := gin.H{"Name": user.Name, "content": user.Address}
	c.JSON(200, content)
}
Example #12
0
func QueryData(c *gin.Context) {
	result := QDataGet(c)
	c.JSON(200, gin.H{
		"status": "ok",
		"data":   result,
	})
}
Example #13
0
func QDataGet(c *gin.Context) []*cmodel.GraphQueryResponse {
	log := logger.Logger()
	startTmp := c.DefaultQuery("startTs", string(time.Now().Unix()-(86400)))
	startTmp2, _ := strconv.Atoi(startTmp)
	startTs := int64(startTmp2)
	endTmp := c.DefaultQuery("endTs", string(time.Now().Unix()))
	endTmp2, _ := strconv.Atoi(endTmp)
	endTs := int64(endTmp2)
	consolFun := c.DefaultQuery("consolFun", "AVERAGE")
	stepTmp := c.DefaultQuery("step", "60")
	step, _ := strconv.Atoi(stepTmp)
	counter := c.DefaultQuery("counter", "cpu.idle")
	endpoints := model.EndpointQuery()
	var result []*cmodel.GraphQueryResponse
	for _, enp := range endpoints {
		q := cmodel.GraphQueryParam{
			Start:     startTs,
			End:       endTs,
			ConsolFun: consolFun,
			Step:      step,
			Endpoint:  enp,
			Counter:   counter,
		}
		res, _ := graph.QueryOne(q)
		log.Debug(fmt.Sprintf("%v, %v, %v", res.Counter, res.Endpoint, len(res.Values)))
		result = append(result, res)
	}
	log.Debug(fmt.Sprintf("%s: %d", "openfaclon query got", len(result)))
	return result
}
Example #14
0
func GetUsers(c *gin.Context) {
	m := Msg{
		Message: "This is GetUsers",
		Status:  200,
	}
	c.JSON(200, m)
}
Example #15
0
func (fc *FrontController) ViewCtr(c *gin.Context) {
	id := c.Param("id")
	var blog VBlogItem
	CKey := fmt.Sprintf("blogitem-%d", id)
	val, ok := Cache.Get(CKey)
	if val != nil && ok == true {
		fmt.Println("Ok, we found cache, Cache Len: ", Cache.Len())
		blog = val.(VBlogItem)
	} else {
		rows, err := DB.Query("Select * from top_article where aid = ?", &id)
		if err != nil {
			log.Fatal(err)
		}
		defer rows.Close()
		var ()
		for rows.Next() {
			err := rows.Scan(&blog.aid, &blog.title, &blog.content, &blog.publish_time, &blog.publish_status)
			if err != nil {
				log.Fatal(err)
			}
		}
		err = rows.Err()
		if err != nil {
			log.Fatal(err)
		}
		Cache.Add(CKey, blog)
	}
	c.HTML(http.StatusOK, "view.html", gin.H{
		"aid":          blog.aid,
		"title":        blog.title.String,
		"content":      template.HTML(blog.content.String),
		"publish_time": blog.publish_time.String,
	})

}
Example #16
0
// AddLog adds a new log entry for the current user.
func AddLog(c *gin.Context) {
	var log models.Log
	err := c.Bind(&log)

	if err == nil {
		if log.Type != "" && log.Description != "" && log.Origin != "" && log.Object != "" {
			uid, err := authentication.GetUserID(c)

			if err == nil {
				log.UserID = uid
				err := configuration.Dbmap.Insert(&log)

				if err == nil {
					showResult(c, 201, log)
					return
				}
			}

			showError(c, 400, fmt.Errorf("adding new log entry failed"))
			return
		}

		showError(c, 422, fmt.Errorf("field(s) are empty"))
		return
	}

	showError(c, 400, fmt.Errorf("adding new log entry failed"))
}
Example #17
0
func (fc *FrontController) HomeCtr(c *gin.Context) {
	page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
	if err != nil {
		log.Fatal(err)
	}
	page -= 1
	if page < 0 {
		page = 0
	}

	prev_page := page
	if prev_page < 1 {
		prev_page = 1
	}
	next_page := page + 2

	rpp := 20
	offset := page * rpp
	CKey := fmt.Sprintf("home-page-%d-rpp-%d", page, rpp)
	var blogList string
	val, ok := Cache.Get(CKey)
	if val != nil && ok == true {
		fmt.Println("Ok, we found cache, Cache Len: ", Cache.Len())
		blogList = val.(string)
	} else {
		rows, err := DB.Query("Select aid, title from top_article where publish_status = 1 order by aid desc limit ? offset ? ", &rpp, &offset)
		if err != nil {
			log.Fatal(err)
		}
		defer rows.Close()
		var (
			aid   int
			title sql.NullString
		)
		for rows.Next() {
			err := rows.Scan(&aid, &title)
			if err != nil {
				log.Fatal(err)
			}
			blogList += fmt.Sprintf(
				"<li><a href=\"/view/%d\">%s</a></li>",
				aid,
				title.String,
			)
		}
		err = rows.Err()
		if err != nil {
			log.Fatal(err)
		}
		Cache.Add(CKey, blogList)
	}
	session := sessions.Default(c)
	username := session.Get("username")
	c.HTML(http.StatusOK, "index.html", gin.H{
		"bloglist":  template.HTML(blogList),
		"username":  username,
		"prev_page": prev_page,
		"next_page": next_page,
	})
}
Example #18
0
// DeleteLog deletes a device based on the identifier.
func DeleteLog(c *gin.Context) {
	id := c.Params.ByName("id")

	if id != "" {
		var log models.Log
		err := c.BindJSON(&log)

		if err == nil {
			uid, err := authentication.GetUserID(c)

			if err == nil {
				log.UserID = uid
				count, err := configuration.Dbmap.Delete(&log)

				if err == nil && count == 1 {
					showSucces(c, fmt.Sprintf("log entry with id %s is deleted", id))
					return
				}
			}
		}

		showError(c, 400, fmt.Errorf("deleting log entry failed"))
		return
	}

	showError(c, 400, fmt.Errorf("deleting log entry failed due to missing identifier"))
}
Example #19
0
func LoginHandler(c *gin.Context) {
	var code int
	var response gin.H

	var loginData loginForm
	c.BindJSON(&loginData)

	errors := loginData.validate()

	if len(errors) == 0 {
		user, authErrors := authOrRegisterUser(loginData)
		if authErrors["password"] != "" {
			code = 422
			response = gin.H{"success": false, "errors": authErrors}
		} else {
			code = 200
			response = gin.H{
				"success": true,
				"new":     user.RestoreCode != "",
				"auth": gin.H{
					"account": user.Email,
					"token":   createUserToken(user),
					"roles":   user.Roles,
				},
			}
		}
	} else {
		code = 422
		response = gin.H{"success": false, "errors": errors}
	}
	c.JSON(code, response)
}
Example #20
0
func lobbyInitializeEndPoin(c *gin.Context) {
	roomIDs, _ := getNewRoomIDs(0, 10)

	roomList := make([]interface{}, len(roomIDs))
	for i, roomID := range roomIDs {
		raw, _ := getRoomRaw(roomID)
		username, err := getUsername(raw.OwnerID)
		if err != nil {
			continue
		}
		roomList[i] = struct {
			ID             int
			Name           string
			Description    string
			CreationTime   string
			LastUpdateTime string
			IsPrivate      bool
			Members        int
			OwnerName      string
		}{
			ID:             raw.ID,
			Name:           raw.Name,
			Description:    raw.Description,
			CreationTime:   time.Unix(raw.CreationTime, 0).Format(TIME_LAYOUT),
			LastUpdateTime: time.Unix(raw.LastUpdateTime, 0).Format(TIME_LAYOUT),
			IsPrivate:      raw.IsPrivate,
			Members:        raw.Members,
			OwnerName:      username,
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"roomList": roomList,
	})
}
func (rest *RestInterface) logs(c *gin.Context) {

	agentID := agentInformation(c)

	db := rest.pool.Get()
	defer db.Close()

	log.Printf("[+] gin: log (gid: %s, nid: %s)\n", agentID.GID, agentID.NID)

	// read body
	content, err := ioutil.ReadAll(c.Request.Body)

	if err != nil {
		log.Println("[-] cannot read body:", err)
		c.JSON(http.StatusInternalServerError, "error")
		return
	}

	// push body to redis
	id := fmt.Sprintf("%s:%s:log", agentID.GID, agentID.NID)
	log.Printf("[+] message destination [%s]\n", id)

	// push message to client queue
	_, err = db.Do("RPUSH", id, content)

	c.JSON(http.StatusOK, "ok")
}
Example #22
0
func saveCurrentChannelEndPoint(c *gin.Context) {
	var json = &struct {
		ID   int    `json:"ID"`
		Type string `json:"Type"`
	}{}

	if c.Bind(json) != nil {
		c.JSON(http.StatusBadRequest, gin.H{"ERR": "WRONG_INPUT"})
		return
	}

	userID64, _ := c.Get("userID")
	userID := userID64.(int)

	cc := &CurrentChannel{
		Type: json.Type,
		ID:   json.ID,
	}

	if peer, ok := peers.get(userID); ok {
		maxMsgId, _ := maxMsgIDofRoom(json.ID)
		cc.LastMsgID = maxMsgId
		peer.ccUpdate(cc)
	}

	if _, err := saveCurrentChannel(userID, cc); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"ERR": "INTERNAL_SERVER_ERROR",
		})
	} else {

		c.JSON(http.StatusOK, gin.H{"SUC": "OK"})
	}
}
Example #23
0
func (m *MessagesController) addOrRemoveLabel(ctx *gin.Context, messageIn *messageJSON, message models.Message, user models.User) {
	if messageIn.Text == "" {
		ctx.AbortWithError(http.StatusBadRequest, errors.New("Invalid Text for label"))
		return
	}
	info := gin.H{}
	if messageIn.Action == "label" {
		addedLabel, err := message.AddLabel(messageIn.Text, messageIn.Option)
		if err != nil {
			log.Errorf("Error while adding a label to a message %s", err)
			ctx.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		info = gin.H{"info": fmt.Sprintf("label %s added to message", addedLabel.Text), "label": addedLabel, "message": message}
	} else if messageIn.Action == "unlabel" {
		err := message.RemoveLabel(messageIn.Text)
		if err != nil {
			log.Errorf("Error while remove a label from a message %s", err)
			ctx.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		info = gin.H{"info": fmt.Sprintf("label %s removed from message", messageIn.Text), "message": message}
	} else {
		ctx.AbortWithError(http.StatusBadRequest, errors.New("Invalid action : "+messageIn.Action))
		return
	}
	go models.WSMessage(&models.WSMessageJSON{Action: messageIn.Action, Username: user.Username, Message: message})
	ctx.JSON(http.StatusCreated, info)
}
Example #24
0
func createRoomEndPoint(c *gin.Context) {
	var json = &struct {
		Name        string `form:"name" 		json:"name" 		binding:"required"`
		Description string `form:"description" json:"description"`
	}{}

	if c.Bind(json) != nil {
		c.JSON(http.StatusBadRequest, gin.H{"ERR": "WRONG_INPUT"})
		return
	}

	userID64, _ := c.Get("userID")

	roomRaw := &RoomData{
		Name:        json.Name,
		Description: json.Description,
		OwnerID:     userID64.(int),
	}

	roomID, err := saveRoomRaw(roomRaw)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"ERR": "INTERNAL_SERVER_ERR"})
		return
	}

	if peer, ok := peers.get(userID64.(int)); ok {
		peer.joinRoom(roomID)
	}

	// return roomid and name
	c.JSON(http.StatusOK, gin.H{
		"ID": roomID, "Name": json.Name,
	})
}
Example #25
0
func DeleteUserInstance(c *gin.Context) {
	db := c.MustGet("db").(gorm.DB)
	consumer := c.MustGet("consumer").(models.User)

	id := c.Params.ByName("id")

	var user models.User

	db.First(&user, id)

	if user.Username == "" {
		response := make(map[string]string)
		response["error"] = "Resource not found."
		c.JSON(404, response)
	} else {
		if (consumer.Admin) || (user.Id == consumer.Id) {
			db.Delete(&user)
			if user.Id != consumer.Id {
				if user.Gravatar == "" {
					user.Gravatar = user.Email
				}
				user.Email = ""
			}
			user.Password = ""
			c.JSON(200, user)
		} else {
			response := make(map[string]string)
			response["error"] = "Invalid credentials."
			c.JSON(401, response)
		}
	}
}
Example #26
0
func GetTableRows(c *gin.Context) {
	limit := 1000 // Number of rows to fetch
	limitVal := c.Request.FormValue("limit")

	if limitVal != "" {
		num, err := strconv.Atoi(limitVal)

		if err != nil {
			c.JSON(400, Error{"Invalid limit value"})
			return
		}

		if num <= 0 {
			c.JSON(400, Error{"Limit should be greater than 0"})
			return
		}

		limit = num
	}

	opts := client.RowsOptions{
		Limit:      limit,
		SortColumn: c.Request.FormValue("sort_column"),
		SortOrder:  c.Request.FormValue("sort_order"),
	}

	res, err := DbClient.TableRows(c.Params.ByName("table"), opts)
	serveResult(res, err, c)
}
Example #27
0
func (pc *NodeController) postDeleteNodeAction(c *gin.Context) {

	id := c.Param("id")

	node, err := models.NodeMapper.FetchOneById(id)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}

	if node == nil {
		c.HTML(http.StatusNotFound, "error_404.html", map[string]interface{}{
			"text": "Node not found",
		})
		return
	}

	if err := models.NodeMapper.Delete(node); err != nil {
		c.HTML(http.StatusInternalServerError, "error_500.html", map[string]interface{}{
			"error": err,
		})
		return
	}

	c.Redirect(http.StatusFound, "/nodes")
}
Example #28
0
func (self *EnvController) Delete(c *gin.Context) {
	username := self.CurrentUser(c)

	if username == "" {
		c.Redirect(http.StatusFound, "/")

		return
	}

	appName := c.Param("appName")
	key := c.PostForm("key")

	fmt.Println(key)

	err := env.Delete(self.etcd, username, appName, key)

	if err != nil {
		fmt.Fprintf(os.Stderr, "%+v\n", err)

		c.HTML(http.StatusInternalServerError, "app.tmpl", gin.H{
			"alert":   true,
			"error":   true,
			"message": "Failed to detele environment variable.",
		})

		return
	}

	c.Redirect(http.StatusSeeOther, "/apps/"+appName)
}
Example #29
0
func GetAddonFiles(ctx *gin.Context) {
	user := ctx.Params.ByName("user")
	repository := ctx.Params.ByName("repository")
	filepath := ctx.Params.ByName("filepath")[1:] // strip the leading "/"
	log.Info("Request for: " + filepath)

	lastReleaseTag, lastReleaseBranch := getLastRelease(user, repository)

	switch filepath {
	case "addons.xml":
		GetAddonsXML(ctx)
		return
	case "addons.xml.md5":
		GetAddonsXMLChecksum(ctx)
		writeChangelog(user, repository)
		return
	case "fanart.jpg":
		fallthrough
	case "icon.png":
		ctx.Redirect(302, fmt.Sprintf(githubUserContentURL+"/"+filepath, user, repository, lastReleaseBranch))
		return
	}

	switch {
	case addonZipRE.MatchString(filepath):
		addonZip(ctx, user, repository, lastReleaseTag)
	case addonChangelogRE.MatchString(filepath):
		addonChangelog(ctx, user, repository)
	default:
		ctx.AbortWithError(404, errors.New(filepath))
	}
}
Example #30
0
func searchRoute(c *gin.Context) {
	q := c.Params.ByName("query")
	if len(q) < 2 {
		four04(c, "Query is too short. Please try a longer query.")
		return
	}

	q = q[1:]

	channels := AllChannels()

	var posts []Itm
	// TODO need to send a PR to Gustavo with support for textscore sorting
	results := Items().Find(bson.M{"$text": bson.M{"$search": q}}).Skip(Offset(c)).Limit(pLimit)

	results.All(&posts)

	if len(posts) == 0 {
		four04(c, "No Articles for query '"+q+"'")
		return
	}

	obj := gin.H{"title": q, "header": q, "items": posts, "posts": posts, "channels": channels}

	if strings.ToLower(c.Request.Header.Get("X-Requested-With")) == "xmlhttprequest" {
		c.HTML(200, "items.html", obj)
	} else {
		c.HTML(200, "full.html", obj)
	}
}