func GetChatMessageReadHandler(start_addr string, notifier *ntf.Notifier, db *d.MainDb, config c.ChatConfig) http.Handler {
	m := GetMartini(config.Name, config.CompanyId, start_addr, db)
	m.Post(start_addr, web.LoginRequired, web.AutHandler.CheckReadRights(config.CompanyId), func(render render.Render, req *http.Request) {
		type Readed struct {
			From string `json:"from"`
		}
		data, err := ioutil.ReadAll(req.Body)
		if err != nil {
			log.Printf("CS QE E: errror at reading req body %v", err)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		readed := Readed{}
		err = json.Unmarshal(data, &readed)
		if err != nil {
			log.Printf("CS QE E: at unmarshal json messages %v\ndata:%s", err, data)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		err = db.Messages.SetAllMessagesRead(readed.From, config.CompanyId)
		if err != nil {
			log.Printf("CS QE E: at unmarshal json messages %v\ndata:%s", err, data)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		render.JSON(200, map[string]interface{}{"ok": true})
	})
	return m
}
func GetChatContactsChangeHandler(start_addr string, notifier *ntf.Notifier, db *d.MainDb, config c.ChatConfig) http.Handler {
	m := GetMartini(config.Name, config.CompanyId, start_addr, db)
	m.Post(start_addr, web.LoginRequired, web.AutHandler.CheckWriteRights(config.CompanyId), func(render render.Render, req *http.Request) {
		type NewContactName struct {
			Id      string `json:"id"`
			NewName string `json:"new_name"`
		}
		ncn := NewContactName{}
		request_body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
			return
		}
		err = json.Unmarshal(request_body, &ncn)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
			return
		}
		err = db.Users.SetUserShowedName(ncn.Id, ncn.NewName)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": err})
			return
		}
		render.JSON(200, map[string]interface{}{"ok": true})

	})
	return m
}
func GetChatUnreadMessagesHandler(start_addr string, notifier *ntf.Notifier, db *d.MainDb, config c.ChatConfig) http.Handler {
	m := GetMartini(config.Name, config.CompanyId, start_addr, db)
	m.Post(start_addr, func(render render.Render, req *http.Request) {
		type NewMessagesReq struct {
			For string `json:"m_for"`
		}
		nmReq := NewMessagesReq{}
		request_body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
			return
		}
		err = json.Unmarshal(request_body, &nmReq)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
			return
		}
		result, err := get_messages(nmReq.For, config.CompanyId, db)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("error in db: %v", err)})
		}
		render.JSON(200, map[string]interface{}{"messages": result})
	})
	return m
}
func GetMessageAdditionalFunctionsHandler(start_addr string, notifier *ntf.Notifier, db *d.MainDb, config c.ChatConfig, chc *CoffeeHouseConfiguration) http.Handler {
	m := GetMartini(config.Name, config.CompanyId, start_addr, db)
	m.Post(start_addr,
		web.LoginRequired,
		web.AutHandler.CheckReadRights(config.CompanyId),
		web.AutHandler.CheckWriteRights(config.CompanyId),
		func(render render.Render, req *http.Request) {
			cfd := CoffeeFunctionData{}
			request_body, err := ioutil.ReadAll(req.Body)
			if err != nil {
				log.Printf("Coffee serv: error at read data: %v", err)
				render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
				return
			}
			err = json.Unmarshal(request_body, &cfd)
			if err != nil {
				log.Printf("Coffee serv: error at unmarshal json: %v", err)
				render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
				return
			}
			log.Printf("Coffee serv: message function: %+v", cfd)
			orderId, err := strconv.ParseInt(cfd.Context.OrderId, 10, 64)
			if err != nil {
				log.Printf("Coffee serv: error at parse int ")
			}
			var result string
			switch cfd.Action {
			case "cancel":
				commands := getCommands(chc, false, false)
				notifier.NotifyTextWithCommands(cfd.Context.UserName, "Ваш заказ отменили!", commands)
				db.Orders.SetActive(orderId, cfd.Context.CompanyName, false)
				result = "Отменено"

			case "start":
				notifier.NotifyText(cfd.Context.UserName, "Ваш заказ в процессе приготовления!")
				result = "В процессе"

			case "end":
				notifier.NotifyText(cfd.Context.UserName, "Ваш заказ готов!")
				db.Orders.SetActive(orderId, cfd.Context.CompanyName, false)
				result = "Окончено"

			case "confirm":
				notifier.NotifyText(cfd.Context.UserName, "Вы уверены что хотите сделать заказ?")
				result = "Подтверждение отправлено"
			}

			db.Messages.SetMessageFunctionUsed(cfd.MessageId, cfd.Action)
			db.Messages.UpdateMessageRelatedOrderState(cfd.MessageId, result)

			found, err := db.Orders.GetByOwner(cfd.Context.UserName, cfd.Context.CompanyName, true)
			render.JSON(200, map[string]interface{}{"ok": true, "result": result, "user_have_active_orders": found != nil})
		})
	return m
}
func GetChatContactsHandler(start_addr string, notifier *ntf.Notifier, db *d.MainDb, config c.ChatConfig) http.Handler {
	m := GetMartini(config.Name, config.CompanyId, start_addr, db)
	m.Post(start_addr, func(render render.Render, req *http.Request) {
		type NewContactsReq struct {
			After int64    `json:"after"`
			Exist []string `json:"exist"`
		}
		cr := NewContactsReq{}
		request_body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
			return
		}
		err = json.Unmarshal(request_body, &cr)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
			return
		}
		contacts, err := getContacts(db, config.CompanyId)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("db err body %v", err)})
			return
		}
		new_contacts := []usrs.Contact{}
		old_contacts := []usrs.Contact{}

		for _, contact := range contacts {
			if u.InS(contact.ID, cr.Exist) {
				if contact.NewMessagesCount > 0 {
					old_contacts = append(old_contacts, contact)
				}
			} else {
				new_contacts = append(new_contacts, contact)
			}
		}
		render.JSON(200, map[string]interface{}{
			"ok":    true,
			"new":   new_contacts,
			"old":   old_contacts,
			"next_": time.Now().Unix(),
		})

	})
	return m
}
func GetChatSendHandler(start_addr string, notifier *ntf.Notifier, db *d.MainDb, config c.ChatConfig, cs *ChatStorage) http.Handler {
	m := GetMartini(config.Name, config.CompanyId, start_addr, db)
	m.Post(start_addr, web.LoginRequired, web.AutHandler.CheckWriteRights(config.CompanyId), func(render render.Render, req *http.Request) {
		type MessageFromF struct {
			From string `json:"from"`
			To   string `json:"to"`
			Body string `json:"body"`
		}

		data, err := ioutil.ReadAll(req.Body)
		if err != nil {
			log.Printf("CS QE E: errror at reading req body %v", err)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		message := MessageFromF{}
		err = json.Unmarshal(data, &message)
		if err != nil {
			log.Printf("CS QE E: at unmarshal json messages %v\ndata:%s", err, data)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		log.Printf("CS message to send: %v", message)
		var messageSID string
		if message.From != "" && message.To != "" && message.Body != "" {
			if message.To == ALL {
				peoples, _ := cs.GetUsersOfCompany(config.CompanyId)
				notifier.SendMessageToPeople(peoples, message.Body)
			} else {
				user, _ := db.Users.GetUserById(message.To)
				if user != nil {
					db.Messages.SetMessagesRead(user.UserId)
					_, resultMessage, _ := notifier.NotifyText(message.To, message.Body)
					resultMessage, _ = db.Messages.GetMessageByMessageId(resultMessage.MessageID)
					messageSID = resultMessage.SID
				}
				db.Messages.SetMessagesAnswered(message.To, config.CompanyId, config.CompanyId)
			}
		} else {
			render.Redirect("/chat")
		}
		render.JSON(200, map[string]interface{}{"ok": true, "message": d.NewMessageForWeb(messageSID, message.From, message.To, message.Body)})
	})
	return m
}
Example #7
0
func main() {
	// parse command line
	var configFile string
	flag.StringVar(&configFile, "config", "/etc/codegrinder/config.json", "Path to the config file")
	var ta, daycare bool
	flag.BoolVar(&ta, "ta", true, "Serve the TA role")
	flag.BoolVar(&daycare, "daycare", true, "Serve the daycare role")
	flag.Parse()

	if !ta && !daycare {
		log.Fatalf("must run at least one role (ta/daycare)")
	}

	// set config defaults
	Config.ToolName = "CodeGrinder"
	Config.ToolID = "codegrinder"
	Config.ToolDescription = "Programming exercises with grading"
	Config.LetsEncryptCache = "/etc/codegrinder/letsencrypt.cache"
	Config.PostgresHost = "/var/run/postgresql"
	Config.PostgresPort = ""
	Config.PostgresUsername = os.Getenv("USER")
	Config.PostgresPassword = ""
	Config.PostgresDatabase = os.Getenv("USER")

	// load config file
	if raw, err := ioutil.ReadFile(configFile); err != nil {
		log.Fatalf("failed to load config file %q: %v", configFile, err)
	} else if err := json.Unmarshal(raw, &Config); err != nil {
		log.Fatalf("failed to parse config file: %v", err)
	}
	Config.SessionSecret = unBase64(Config.SessionSecret)
	Config.DaycareSecret = unBase64(Config.DaycareSecret)

	// set up martini
	r := martini.NewRouter()
	m := martini.New()
	m.Logger(log.New(os.Stderr, "", log.LstdFlags))
	m.Use(martini.Logger())
	m.Use(martini.Recovery())
	m.Use(martini.Static(Config.StaticDir, martini.StaticOptions{SkipLogging: true}))
	m.MapTo(r, (*martini.Routes)(nil))
	m.Action(r.Handle)

	m.Use(render.Renderer(render.Options{IndentJSON: true}))

	store := sessions.NewCookieStore([]byte(Config.SessionSecret))
	m.Use(sessions.Sessions(CookieName, store))

	// sessions expire June 30 and December 31
	go func() {
		for {
			now := time.Now()

			// expire at the end of the calendar year
			expires := time.Date(now.Year(), time.December, 31, 23, 59, 59, 0, time.Local)

			if expires.Sub(now).Hours() < 14*24 {
				// are we within 2 weeks of the end of the year? probably prepping for spring,
				// so expire next June 30 instead
				expires = time.Date(now.Year()+1, time.June, 30, 23, 59, 59, 0, time.Local)
			} else if expires.Sub(now).Hours() > (365/2+14)*24 {
				// is it still more than 2 weeks before June 30? probably in spring semester,
				// so expire this June 30 instead
				expires = time.Date(now.Year(), time.June, 30, 23, 59, 59, 0, time.Local)
			}
			store.Options(sessions.Options{Path: "/", Secure: true, MaxAge: int(expires.Sub(now).Seconds())})
			time.Sleep(11 * time.Minute)
		}
	}()

	// set up TA role
	if ta {
		// make sure relevant secrets are included in config file
		if Config.LTISecret == "" {
			log.Fatalf("cannot run TA role with no LTISecret in the config file")
		}
		if Config.SessionSecret == "" {
			log.Fatalf("cannot run TA role with no SessionSecret in the config file")
		}
		if Config.DaycareSecret == "" {
			log.Fatalf("cannot run with no DaycareSecret in the config file")
		}

		// set up the database
		db := setupDB(Config.PostgresHost, Config.PostgresPort, Config.PostgresUsername, Config.PostgresPassword, Config.PostgresDatabase)

		// martini service: wrap handler in a transaction
		withTx := func(c martini.Context, w http.ResponseWriter) {
			// start a transaction
			tx, err := db.Begin()
			if err != nil {
				loggedHTTPErrorf(w, http.StatusInternalServerError, "db error starting transaction: %v", err)
				return
			}

			// pass it on to the main handler
			c.Map(tx)
			c.Next()

			// was it a successful result?
			rw := w.(martini.ResponseWriter)
			if rw.Status() < http.StatusBadRequest {
				// commit the transaction
				if err := tx.Commit(); err != nil {
					loggedHTTPErrorf(w, http.StatusInternalServerError, "db error committing transaction: %v", err)
					return
				}
			} else {
				// rollback
				log.Printf("rolling back transaction")
				if err := tx.Rollback(); err != nil {
					loggedHTTPErrorf(w, http.StatusInternalServerError, "db error rolling back transaction: %v", err)
					return
				}
			}
		}

		// martini service: to require an active logged-in session
		auth := func(w http.ResponseWriter, session sessions.Session) {
			if userID := session.Get("id"); userID == nil {
				loggedHTTPErrorf(w, http.StatusUnauthorized, "authentication: no user ID found in session")
				return
			}
		}

		// martini service: include the current logged-in user (requires withTx and auth)
		withCurrentUser := func(c martini.Context, w http.ResponseWriter, tx *sql.Tx, session sessions.Session) {
			rawID := session.Get("id")
			if rawID == nil {
				loggedHTTPErrorf(w, http.StatusInternalServerError, "cannot find user ID in session")
				return
			}
			userID, ok := rawID.(int64)
			if !ok {
				session.Clear()
				loggedHTTPErrorf(w, http.StatusInternalServerError, "error extracting user ID from session")
				return
			}

			// load the user record
			user := new(User)
			if err := meddler.Load(tx, "users", user, userID); err != nil {
				if err == sql.ErrNoRows {
					loggedHTTPErrorf(w, http.StatusUnauthorized, "user %d not found", userID)
					return
				}
				loggedHTTPErrorf(w, http.StatusInternalServerError, "db error: %v", err)
				return
			}

			// map the current user to the request context
			c.Map(user)
		}

		// martini service: require logged in user to be an administrator (requires withCurrentUser)
		administratorOnly := func(w http.ResponseWriter, currentUser *User) {
			if !currentUser.Admin {
				loggedHTTPErrorf(w, http.StatusUnauthorized, "user %d (%s) is not an administrator", currentUser.ID, currentUser.Email)
				return
			}
		}

		// martini service: require logged in user to be an author or administrator (requires withCurrentUser)
		authorOnly := func(w http.ResponseWriter, tx *sql.Tx, currentUser *User) {
			if currentUser.Admin {
				return
			}
			if !currentUser.Author {
				loggedHTTPErrorf(w, http.StatusUnauthorized, "user %d (%s) is not an author", currentUser.ID, currentUser.Name)
				return
			}
		}

		// version
		r.Get("/v2/version", func(w http.ResponseWriter, render render.Render) {
			render.JSON(http.StatusOK, &CurrentVersion)
		})

		// LTI
		r.Get("/v2/lti/config.xml", GetConfigXML)
		r.Post("/v2/lti/problem_sets", binding.Bind(LTIRequest{}), checkOAuthSignature, withTx, LtiProblemSets)
		r.Post("/v2/lti/problem_sets/:unique", binding.Bind(LTIRequest{}), checkOAuthSignature, withTx, LtiProblemSet)

		// problem bundles--for problem creation only
		r.Post("/v2/problem_bundles/unconfirmed", auth, withTx, withCurrentUser, authorOnly, binding.Json(ProblemBundle{}), PostProblemBundleUnconfirmed)
		r.Post("/v2/problem_bundles/confirmed", auth, withTx, withCurrentUser, authorOnly, binding.Json(ProblemBundle{}), PostProblemBundleConfirmed)
		r.Put("/v2/problem_bundles/:problem_id", auth, withTx, withCurrentUser, authorOnly, binding.Json(ProblemBundle{}), PutProblemBundle)

		// problem set bundles--for problem set creation only
		r.Post("/v2/problem_set_bundles", auth, withTx, withCurrentUser, authorOnly, binding.Json(ProblemSetBundle{}), PostProblemSetBundle)

		// problem types
		r.Get("/v2/problem_types", auth, GetProblemTypes)
		r.Get("/v2/problem_types/:name", auth, GetProblemType)

		// problems
		r.Get("/v2/problems", auth, withTx, withCurrentUser, GetProblems)
		r.Get("/v2/problems/:problem_id", auth, withTx, withCurrentUser, GetProblem)
		r.Get("/v2/problems/:problem_id/steps", auth, withTx, withCurrentUser, GetProblemSteps)
		r.Get("/v2/problems/:problem_id/steps/:step", auth, withTx, withCurrentUser, GetProblemStep)
		r.Delete("/v2/problems/:problem_id", auth, withTx, withCurrentUser, administratorOnly, DeleteProblem)

		// problem sets
		r.Get("/v2/problem_sets", auth, withTx, withCurrentUser, GetProblemSets)
		r.Get("/v2/problem_sets/:problem_set_id", auth, withTx, withCurrentUser, GetProblemSet)
		r.Get("/v2/problem_sets/:problem_set_id/problems", auth, withTx, withCurrentUser, GetProblemSetProblems)
		r.Delete("/v2/problem_sets/:problem_set_id", auth, withTx, withCurrentUser, administratorOnly, DeleteProblemSet)

		// courses
		r.Get("/v2/courses", auth, withTx, withCurrentUser, GetCourses)
		r.Get("/v2/courses/:course_id", auth, withTx, withCurrentUser, GetCourse)
		r.Delete("/v2/courses/:course_id", auth, withTx, withCurrentUser, administratorOnly, DeleteCourse)

		// users
		r.Get("/v2/users", auth, withTx, withCurrentUser, GetUsers)
		r.Get("/v2/users/me", auth, withTx, withCurrentUser, GetUserMe)
		r.Get("/v2/users/me/cookie", auth, GetUserMeCookie)
		r.Get("/v2/users/:user_id", auth, withTx, withCurrentUser, GetUser)
		r.Get("/v2/courses/:course_id/users", auth, withTx, withCurrentUser, GetCourseUsers)
		r.Delete("/v2/users/:user_id", auth, withTx, withCurrentUser, administratorOnly, DeleteUser)

		// assignments
		r.Get("/v2/users/:user_id/assignments", auth, withTx, withCurrentUser, GetUserAssignments)
		r.Get("/v2/courses/:course_id/users/:user_id/assignments", auth, withTx, withCurrentUser, GetCourseUserAssignments)
		r.Get("/v2/assignments/:assignment_id", auth, withTx, withCurrentUser, GetAssignment)
		r.Delete("/v2/assignments/:assignment_id", auth, withTx, withCurrentUser, administratorOnly, DeleteAssignment)

		// commits
		r.Get("/v2/assignments/:assignment_id/problems/:problem_id/commits/last", auth, withTx, withCurrentUser, GetAssignmentProblemCommitLast)
		r.Get("/v2/assignments/:assignment_id/problems/:problem_id/steps/:step/commits/last", auth, withTx, withCurrentUser, GetAssignmentProblemStepCommitLast)
		r.Delete("/v2/commits/:commit_id", auth, withTx, withCurrentUser, administratorOnly, DeleteCommit)

		// commit bundles
		r.Post("/v2/commit_bundles/unsigned", auth, withTx, withCurrentUser, binding.Json(CommitBundle{}), PostCommitBundlesUnsigned)
		r.Post("/v2/commit_bundles/signed", auth, withTx, withCurrentUser, binding.Json(CommitBundle{}), PostCommitBundlesSigned)
	}

	// set up daycare role
	if daycare {
		// make sure relevant secrets are included in config file
		if Config.DaycareSecret == "" {
			log.Fatalf("cannot run with no DaycareSecret in the config file")
		}

		// attach to docker and try a ping
		var err error
		dockerClient, err = docker.NewVersionedClient("unix:///var/run/docker.sock", "1.18")
		if err != nil {
			log.Fatalf("NewVersionedClient: %v", err)
		}
		if err = dockerClient.Ping(); err != nil {
			log.Fatalf("Ping: %v", err)
		}

		r.Get("/v2/sockets/:problem_type/:action", SocketProblemTypeAction)
	}

	// start redirecting http calls to https
	log.Printf("starting http -> https forwarder")
	go http.ListenAndServe(":http", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// get the address of the client
		addr := r.Header.Get("X-Real-IP")
		if addr == "" {
			addr = r.Header.Get("X-Forwarded-For")
			if addr == "" {
				addr = r.RemoteAddr
			}
		}

		// make sure the request is for the right host name
		if Config.Hostname != r.Host {
			loggedHTTPErrorf(w, http.StatusNotFound, "http request to invalid host: %s", r.Host)
			return
		}
		var u url.URL = *r.URL
		u.Scheme = "https"
		u.Host = Config.Hostname
		log.Printf("redirecting http request from %s to %s", addr, u.String())
		http.Redirect(w, r, u.String(), http.StatusMovedPermanently)
	}))

	// set up letsencrypt
	lem := letsencrypt.Manager{}
	if err := lem.CacheFile(Config.LetsEncryptCache); err != nil {
		log.Fatalf("Setting up LetsEncrypt: %v", err)
	}
	lem.SetHosts([]string{Config.Hostname})
	if !lem.Registered() {
		log.Printf("registering with letsencrypt")
		if err := lem.Register(Config.LetsEncryptEmail, nil); err != nil {
			log.Fatalf("Registering with LetsEncrypt: %v", err)
		}
	}

	// start the https server
	log.Printf("accepting https connections")
	server := &http.Server{
		Addr:    ":https",
		Handler: m,
		TLSConfig: &tls.Config{
			MinVersion:     tls.VersionTLS10,
			GetCertificate: lem.GetCertificate,
		},
	}
	if err := server.ListenAndServeTLS("", ""); err != nil {
		log.Fatalf("ListenAndServeTLS: %v", err)
	}
}
func Run(config c.QuestConfig, qs *QuestStorage, ntf *ntf.Notifier, additionalNotifier *ntf.Notifier) {
	m := martini.New()
	m.Use(w.NonJsonLogger())
	m.Use(martini.Recovery())
	m.Use(render.Renderer(render.Options{
		Directory:  "templates/quests",
		Layout:     "layout",
		Extensions: []string{".tmpl", ".html"},
		Charset:    "UTF-8",
		IndentJSON: true,
		IndentXML:  true,
		Funcs: []template.FuncMap{
			template.FuncMap{
				"eq_s": func(a, b string) bool {
					return a == b
				},
				"stamp_date": func(t time.Time) string {
					return t.Format(time.Stamp)
				},
			},
		},
	}))

	m.Use(auth.BasicFunc(func(username, password string) bool {
		pwd, ok := users[username]
		return ok && pwd == password
	}))

	m.Use(martini.Static("static"))

	r := martini.NewRouter()

	r.Get("/", func(user auth.User, render render.Render) {
		render.HTML(200, "readme", map[string]interface{}{})
	})

	r.Get("/new_keys", func(render render.Render) {
		render.HTML(200, "new_keys", GetKeysErrorInfo("", qs))
	})

	r.Post("/add_key", func(user auth.User, render render.Render, request *http.Request) {
		start_key := strings.TrimSpace(request.FormValue("start-key"))
		next_key := strings.TrimSpace(request.FormValue("next-key"))
		description := request.FormValue("description")

		log.Printf("QUESTS WEB add key %s -> %s -> %s", start_key, description, next_key)
		if start_key != "" && description != "" {
			key, err := qs.AddStep(start_key, description, next_key)
			if key != nil && err != nil {
				render.HTML(200, "new_keys", GetKeysErrorInfo("Такой ключ уже существует. Используйте изменение ключа если хотите его изменить.", qs))
				return
			}
		} else {

			render.HTML(200, "new_keys", GetKeysErrorInfo("Невалидные значения ключа или ответа", qs))
			return
		}
		render.Redirect("/new_keys")
	})

	r.Post("/delete_key/:key", func(params martini.Params, render render.Render) {
		key := params["key"]
		err := qs.DeleteStep(key)
		log.Printf("QUESTS WEB will delete %v (%v)", key, err)
		render.Redirect("/new_keys")
	})

	r.Post("/update_key/:key", func(params martini.Params, render render.Render, request *http.Request) {
		key_id := params["key"]

		start_key := strings.TrimSpace(request.FormValue("start-key"))
		next_key := strings.TrimSpace(request.FormValue("next-key"))
		description := request.FormValue("description")

		err := qs.UpdateStep(key_id, start_key, description, next_key)
		log.Printf("QUESTS WEB was update key %s %s %s %s\n err? %v", key_id, start_key, description, next_key, err)
		render.Redirect("/new_keys")
	})

	r.Get("/delete_key_all", func(render render.Render) {
		qs.Steps.RemoveAll(bson.M{})
		render.Redirect("/new_keys")
	})

	xlsFileReg := regexp.MustCompile(".+\\.xlsx?")

	r.Post("/load/up", func(render render.Render, request *http.Request) {
		file, header, err := request.FormFile("file")

		log.Printf("QS: Form file information: file: %+v \nheader:%v, %v\nerr:%v", file, header.Filename, header.Header, err)

		if err != nil {
			render.HTML(200, "new_keys", GetKeysErrorInfo(fmt.Sprintf("Ошибка загрузки файлика: %v", err), qs))
			return
		}
		defer file.Close()

		data, err := ioutil.ReadAll(file)
		if err != nil {
			render.HTML(200, "new_keys", GetKeysErrorInfo(fmt.Sprintf("Ошибка загрузки файлика: %v", err), qs))
			return
		}

		if xlsFileReg.MatchString(header.Filename) {
			xlFile, err := xlsx.OpenBinary(data)

			if err != nil || xlFile == nil {
				render.HTML(200, "new_keys", GetKeysErrorInfo(fmt.Sprintf("Ошибка обработки файлика: %v", err), qs))
				return
			}
			skip_rows, errsr := strconv.Atoi(request.FormValue("skip-rows"))
			skip_cols, errsc := strconv.Atoi(request.FormValue("skip-cols"))
			if errsr != nil || errsc != nil {
				render.HTML(200, "new_keys", GetKeysErrorInfo("Не могу распознать количества столбцов и строк пропускаемых :(", qs))
				return
			}
			log.Printf("QS: Will process file: %+v, err: %v \n with skipped rows: %v, cols: %v", xlFile, err, skip_rows, skip_cols)
			parse_res, errp := w.ParseExportXlsx(xlFile, skip_rows, skip_cols)
			if errp != nil {
				render.HTML(200, "new_keys", GetKeysErrorInfo("Ошибка в парсинге файла:(", qs))
				return
			}
			res, val_err := ValidateKeys(parse_res)
			if val_err != nil {
				render.HTML(200, "new_keys", GetKeysErrorInfo(val_err.Error(), qs))
				return
			}
			for _, prel := range parse_res {
				qs.AddStep(prel[0], prel[1], prel[2])
			}
			render.HTML(200, "new_keys", GetKeysTeamsInfo(res, qs))
		} else {
			render.HTML(200, "new_keys", GetKeysErrorInfo("Файл имеет не то расширение :(", qs))
		}

		render.Redirect("/new_keys")
	})

	r.Get("/chat", func(render render.Render, params martini.Params, req *http.Request) {
		var with string
		result_data := map[string]interface{}{}
		query := req.URL.Query()
		for key, value := range query {
			if key == "with" && len(value) > 0 {
				with = value[0]
				log.Printf("QSERV: with found is: %v", with)
				break
			}
		}
		type Collocutor struct {
			IsTeam   bool
			IsMan    bool
			IsAll    bool
			IsWinner bool
			WinTime  string
			Info     interface{}
			Name     string
		}
		collocutor := Collocutor{}

		var messages []Message

		if with != ALL && with != ALL_TEAM_MEMBERS {
			if team, _ := qs.GetTeamByName(with); team != nil {
				type TeamInfo struct {
					FoundedKeys []string
					Members     []TeamMember
					AllKeys     []Step
				}

				collocutor.Name = team.Name
				collocutor.IsTeam = true
				collocutor.IsWinner = team.Winner
				if collocutor.IsWinner {
					tm := time.Unix(team.WinTime, 0)
					collocutor.WinTime = tm.Format("Mon 15:04:05")
				}
				members, _ := qs.GetMembersOfTeam(team.Name)
				keys, _ := qs.GetSteps(bson.M{"for_team": team.Name})
				keys = SortSteps(keys)
				collocutor.Info = TeamInfo{FoundedKeys: team.FoundKeys, Members: members, AllKeys: keys}

				messages, _ = qs.GetMessages(bson.M{
					"$or": []bson.M{
						bson.M{"from": team.Name},
						bson.M{"to": team.Name},
					},
				})
			} else {
				if peoples, _ := qs.GetPeoples(bson.M{"user_id": with}); len(peoples) > 0 {
					man := peoples[0]
					collocutor.IsMan = true
					collocutor.Name = man.Name
					collocutor.Info = man

					messages, _ = qs.GetMessages(bson.M{
						"$or": []bson.M{
							bson.M{"from": man.UserId},
							bson.M{"to": man.UserId},
						},
					})
					for i, _ := range messages {
						if messages[i].From != ME {
							messages[i].From = man.Name
						}
					}
				} else {
					with = "all"
				}
			}
		}

		if strings.HasPrefix(with, "all") {
			collocutor.IsAll = true
			collocutor.Name = with
			messages, _ = qs.GetMessages(bson.M{"to": with})
		}

		//log.Printf("QS i return this messages: %+v", messages)
		result_data["with"] = with
		result_data["collocutor"] = collocutor
		if len(messages) > 100 {
			messages = messages[0:100]
		}
		result_data["messages"] = messages

		qs.SetMessagesRead(with)

		all_teams, _ := qs.GetAllTeams()
		if contacts, err := qs.GetContacts(all_teams); err == nil {
			result_data["contacts"] = contacts
		}

		render.HTML(200, "chat", result_data)
	})

	r.Post("/send", func(render render.Render, req *http.Request) {
		type MessageFromF struct {
			From string `json:"from"`
			To   string `json:"to"`
			Body string `json:"body"`
		}
		data, err := ioutil.ReadAll(req.Body)
		if err != nil {
			log.Printf("QS QE E: errror at reading req body %v", err)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		message := MessageFromF{}
		err = json.Unmarshal(data, &message)
		if err != nil {
			log.Printf("QS QE E: at unmarshal json messages %v\ndata:%s", err, data)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		log.Printf("QS I see this data for send message from f:\n %+v", message)

		var result Message
		if message.From != "" && message.To != "" && message.Body != "" {
			if message.To == "all" {
				peoples, _ := qs.GetPeoples(bson.M{})
				log.Printf("QSERV: will send [%v] to all %v peoples", message.Body, len(peoples))
				SendMessagesToPeoples(peoples, ntf, message.Body)
			} else if message.To == "all_team_members" {
				peoples, _ := qs.GetAllTeamMembers()
				log.Printf("QSERV: will send [%v] to all team members %v peoples", message.Body, len(peoples))
				SendMessagesToPeoples(peoples, ntf, message.Body)
			} else {
				team, _ := qs.GetTeamByName(message.To)
				if team == nil {
					man, _ := qs.GetManByUserId(message.To)
					if man != nil {
						log.Printf("QSERV: will send [%v] to %v", message.Body, man.UserId)
						go ntf.NotifyText(man.UserId, message.Body)
					}
				} else {
					peoples, _ := qs.GetMembersOfTeam(team.Name)
					log.Printf("QSERV: will send [%v] to team members of %v team to %v peoples", message.Body, team.Name, len(peoples))
					SendMessagesToPeoples(peoples, ntf, message.Body)
				}
			}
			result, err = qs.StoreMessage(message.From, message.To, message.Body, false)
			if err != nil {
				log.Printf("QSERV: error at storing message %v", err)
				render.JSON(200, map[string]interface{}{"ok": false})
				return
			}
			result.TimeFormatted = result.Time.Format(time.Stamp)

		} else {
			render.JSON(200, map[string]interface{}{"ok": false})
		}
		render.JSON(200, map[string]interface{}{"ok": true, "message": result})

	})

	r.Post("/messages", func(render render.Render, req *http.Request) {
		type NewMessagesReq struct {
			For   string `json:"m_for"`
			After int64  `json:"after"`
		}
		q := NewMessagesReq{}
		request_body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
			return
		}
		err = json.Unmarshal(request_body, &q)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
			return
		}

		messages, err := qs.GetMessages(bson.M{"from": q.For, "time_stamp": bson.M{"$gt": q.After}})
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("error in db: %v", err)})
			return
		}

		for i, message := range messages {
			team, _ := qs.GetTeamByName(message.From)
			if team != nil {
				messages[i].From = team.Name
			} else {
				man, _ := qs.GetManByUserId(message.From)
				if man != nil {
					messages[i].From = man.Name
				}

			}
			messages[i].TimeFormatted = message.Time.Format(time.Stamp)
		}

		render.JSON(200, map[string]interface{}{"messages": messages, "next_": time.Now().Unix()})
	})

	r.Post("/contacts", func(render render.Render, req *http.Request) {
		type NewContactsReq struct {
			After int64    `json:"after"`
			Exist []string `json:"exist"`
		}
		cr := NewContactsReq{}
		request_body, err := ioutil.ReadAll(req.Body)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
			return
		}
		err = json.Unmarshal(request_body, &cr)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
			return
		}
		contacts, err := qs.GetContactsAfter(cr.After)
		if err != nil {
			render.JSON(500, map[string]interface{}{"ok": false, "detail": err})
			return
		}
		new_contacts := []Contact{}
		old_contacts := []Contact{}

		for _, contact := range contacts {
			if utils.InS(contact.ID, cr.Exist) {
				old_contacts = append(old_contacts, contact)
			} else {
				new_contacts = append(new_contacts, contact)
			}
		}
		render.JSON(200, map[string]interface{}{
			"ok":    true,
			"new":   new_contacts,
			"old":   old_contacts,
			"next_": time.Now().Unix(),
		})

	})

	r.Get("/manage", func(render render.Render, req *http.Request) {
		configResult, err := qs.GetMessageConfiguration(config.Chat.CompanyId)
		if err != nil {
			log.Printf("QS E: Can not load quest configuration for %v, because: %v", config.Chat.CompanyId, err)
		}
		render.HTML(200, "manage", map[string]interface{}{"config": configResult})
	})

	r.Post("/manage", binding.Bind(QuestMessageConfiguration{}), func(qmc QuestMessageConfiguration, ren render.Render, req *http.Request) {
		if req.FormValue("to-winner-on") == "on" {
			qmc.EndMessageForWinnersActive = true
		}
		if req.FormValue("to-not-winner-on") == "on" {
			qmc.EndMessageForNotWinnersActive = true
		}
		if req.FormValue("to-all-on") == "on" {
			qmc.EndMessageForAllActive = true
		}
		log.Printf("QS Manage: %+v", qmc)
		qmc.CompanyId = config.Chat.CompanyId
		err := qs.SetMessageConfiguration(qmc, true)
		if err != nil {
			log.Printf("QS ERROR at update quest message configuration for [%v], because: %v", qmc.CompanyId, err)
		}
		ren.Redirect("/manage", 302)
	})

	r.Post("/start_quest", func(ren render.Render) {
		qmc, err := qs.GetMessageConfiguration(config.Chat.CompanyId)
		if err != nil {
			log.Printf("QS E: Can not load quest configuration for %v, because: %v", config.Chat.CompanyId, err)
			ren.JSON(500, map[string]interface{}{"ok": false, "detail": err})
			return
		}
		if qmc.Started == false {
			qs.SetQuestStarted(config.Chat.CompanyId, true)
			ren.JSON(200, map[string]interface{}{"ok": true})
		} else {
			ren.JSON(200, map[string]interface{}{"ok": false, "detail": "already started"})
		}
	})

	r.Post("/stop_quest", func(ren render.Render) {
		qmc, err := qs.GetMessageConfiguration(config.Chat.CompanyId)
		if err != nil {
			log.Printf("QS E: Can not load quest configuration for %v, because: %v", config.Chat.CompanyId, err)
			ren.JSON(500, map[string]interface{}{"ok": false, "detail": err})
			return
		}
		if qmc.Started == true {
			qs.SetQuestStarted(config.Chat.CompanyId, false)
			teams, err := qs.GetAllTeams()
			if err != nil {
				log.Printf("QS QE E: errror at getting teams %v", err)
			}
			if qmc.EndMessageForAllActive == true {
				for _, team := range teams {
					log.Printf("QS Will send message to team: %v from Klichat", team.Name)
					members, _ := qs.GetMembersOfTeam(team.Name)
					SendMessagesToPeoples(members, additionalNotifier, qmc.EndMessageForAll)
				}
			}
			if qmc.EndMessageForWinnersActive == true {
				for _, team := range teams {
					if team.Winner == true {
						log.Printf("QS Will send WIN message to team: %v from quest", team.Name)
						members, _ := qs.GetMembersOfTeam(team.Name)
						SendMessagesToPeoples(members, ntf, qmc.EndMessageForWinners)
					}
				}
			}
			if qmc.EndMessageForNotWinnersActive == true {
				for _, team := range teams {
					if team.Winner == false {
						log.Printf("QS Will send NOT WIN message to team: %v from quest", team.Name)
						members, _ := qs.GetMembersOfTeam(team.Name)
						SendMessagesToPeoples(members, ntf, qmc.EndMessageForNotWinners)
					}
				}
			}

			ren.JSON(200, map[string]interface{}{"ok": true})
		} else {
			ren.JSON(200, map[string]interface{}{"ok": false, "detail": "already stopped"})
		}

	})

	r.Get("/delete_chat/:between", func(params martini.Params, render render.Render, req *http.Request) {
		between := params["between"]
		qs.Messages.RemoveAll(bson.M{"$or": []bson.M{bson.M{"from": between}, bson.M{"to": between}}})
		render.Redirect(fmt.Sprintf("/chat?with=%v", between))
	})

	r.Post("/send_messages_at_quest_end", func(render render.Render, req *http.Request) {
		type Messages struct {
			Text    string   `json:"text"`
			Teams   []string `json:"teams"`
			Exclude bool     `json:"exclude"`
		}
		messages := Messages{}
		data, err := ioutil.ReadAll(req.Body)
		if err != nil {
			log.Printf("QS QE E: errror at reading req body %v", err)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		err = json.Unmarshal(data, &messages)
		if err != nil {
			log.Printf("QS QE E: at unmarshal json messages %v", err)
			render.JSON(500, map[string]interface{}{"error": err})
			return
		}
		log.Printf("QS I see this data for send messages at quest end:\n %+v", messages)

		if messages.Exclude {
			teams, err := qs.GetAllTeams()
			if err != nil {
				log.Printf("QS QE E: errror at getting teams %v", err)
				render.JSON(500, map[string]interface{}{"error": err})
				return
			}
			for _, team := range teams {
				if !utils.InS(team.Name, messages.Teams) {
					log.Printf("QS Will send message to team: %v", team.Name)
					members, _ := qs.GetMembersOfTeam(team.Name)
					SendMessagesToPeoples(members, additionalNotifier, messages.Text)
				}
			}
			render.JSON(200, map[string]interface{}{"ok": true})
		} else {
			for _, team_name := range messages.Teams {
				members, err := qs.GetMembersOfTeam(team_name)
				if err != nil {
					log.Printf("QS QE E: errror at getting team members %v", err)
					continue
				}
				log.Printf("QS Will send message to team: %v", team_name)
				SendMessagesToPeoples(members, additionalNotifier, messages.Text)
			}
			render.JSON(200, map[string]interface{}{"ok": true})
		}

	})

	r.Post("/delete_all_keys", func(render render.Render, req *http.Request) {
		//1. Steps or keys:
		si, _ := qs.Steps.RemoveAll(bson.M{})
		//2 Peoples
		pi, _ := qs.Peoples.UpdateAll(bson.M{
			"$and": []bson.M{
				bson.M{"$or": []bson.M{
					bson.M{"is_passerby": false},
					bson.M{"is_passerby": bson.M{"$exists": false}},
				}},
				bson.M{"$or": []bson.M{
					bson.M{"team_name": bson.M{"$exists": true}},
					bson.M{"team_sid": bson.M{"$exists": true}},
				}},
			},
		},
			bson.M{
				"$set":   bson.M{"is_passerby": true},
				"$unset": bson.M{"team_name": "", "team_sid": ""},
			})
		//3 teams and messages
		teams := []Team{}
		qs.Teams.Find(bson.M{}).All(&teams)
		tc := 0
		mc := 0
		for _, team := range teams {
			mri, _ := qs.Messages.RemoveAll(bson.M{
				"$or": []bson.M{
					bson.M{"from": team.Name},
					bson.M{"to": team.Name},
				}})
			mc += mri.Removed

			qs.Teams.RemoveId(team.ID)
			tc += 1
		}
		render.JSON(200, map[string]interface{}{
			"ok":               true,
			"steps_removed":    si.Removed,
			"peoples_updated":  pi.Updated,
			"teams_removed":    tc,
			"messages_removed": mc,
		})
	})

	r.Post("/founded_keys", func(ren render.Render, req *http.Request) {
		type T struct {
			Name string `json:"team"`
		}
		t := T{}
		body, _ := ioutil.ReadAll(req.Body)
		json.Unmarshal(body, &t)
		steps, _ := qs.GetSteps(bson.M{"for_team": t.Name, "is_found": true})
		ren.JSON(200, map[string]interface{}{"keys": steps})
	})

	type FoundKey struct {
		Name        string `bson:"name" json:"name"`
		Found       bool   `bson:"found" json:"found"`
		Id          string `json:"id"`
		Description string `json:"description"`
	}
	type TeamInfo struct {
		TeamName string     `bson:"team_name" json:"team_name"`
		Keys     []FoundKey `json:"keys"`
		Steps    []Step     `bson:"steps"`
	}

	r.Get("/info_page", func(ren render.Render, req *http.Request) {
		result := []TeamInfo{}
		err := qs.Steps.Pipe([]bson.M{
			bson.M{"$group": bson.M{
				"_id":       "$for_team",
				"team_name": bson.M{"$first": "$for_team"},
				"steps": bson.M{"$push": bson.M{
					"_id":         "$_id",
					"is_found":    "$is_found",
					"next_key":    "$next_key",
					"start_key":   "$start_key",
					"description": "$description",
				}}}},
			bson.M{"$sort": bson.M{
				"team_name": 1}},
		}).All(&result)
		if err != nil {
			log.Printf("QS Error at aggregate info page %v", err)
		}
		for ti, teamInfo := range result {
			steps := SortSteps(teamInfo.Steps)
			keys := []FoundKey{}
			for _, step := range steps {
				keys = append(keys, FoundKey{Name: step.StartKey, Found: step.IsFound, Id: step.ID.Hex(), Description: step.Description})
			}
			result[ti].Keys = keys
			result[ti].Steps = []Step{}
		}
		ren.HTML(200, "info_page", map[string]interface{}{"teams": result})
	})
	r.Post("/info_page/update", func(ren render.Render, req *http.Request) {
		found_keys, err := qs.GetSteps(bson.M{"is_found": true})
		if err != nil {
			ren.JSON(500, map[string]interface{}{"ok": false, "error": err.Error()})
		}
		type UpdateKeyResult struct {
			Id string `json:"id"`
		}
		result := []UpdateKeyResult{}
		for _, key := range found_keys {
			result = append(result, UpdateKeyResult{Id: key.ID.Hex()})
		}
		ren.JSON(200, map[string]interface{}{"ok": true, "foundKeys": result})
	})

	r.Post("/start_quest", func(ren render.Render, req *http.Request) {
		ren.JSON(200, map[string]interface{}{"ok": true})
	})
	r.Post("/stop_quest")

	//m.MapTo(r, (*martini.Routes)(nil))
	log.Printf("Will start web server for quest at: %v", config.WebPort)
	m.Action(r.Handle)
	m.RunOnAddr(config.WebPort)
}
func Run(addr string, db *d.MainDb, qs *quests.QuestStorage, vdh *voting.VotingDataHandler, ntf *ntf.Notifier, cfg c.Configuration) {
	m := martini.New()
	m.Use(w.NonJsonLogger())
	m.Use(martini.Recovery())
	m.Use(martini.Static("static"))
	m.Use(render.Renderer(render.Options{
		Directory: "templates/console",
		//Layout: "console/layout",
		Extensions: []string{".tmpl", ".html"},
		Charset:    "UTF-8",
		IndentJSON: true,
		IndentXML:  true,
		Funcs: []template.FuncMap{
			template.FuncMap{
				"eq_s": func(a, b string) bool {
					return a == b
				},
				"stamp_date": func(t time.Time) string {
					return t.Format(time.Stamp)
				},
				"chat_with": func(with string) string {
					result := fmt.Sprintf("/chat?with=%v", with)
					return result
				},
				"me": func() string {
					return ME
				},
				"is_message_": func(msg d.MessageWrapper, attrName string) bool {
					return msg.IsAttrPresent(attrName)
				},
				"has_additional_data": func(msg d.MessageWrapper) bool {
					return len(msg.AdditionalData) > 0
				},
				"is_additional_data_valid": func(ad d.AdditionalDataElement) bool {
					return ad.Value != ""
				},
				"from_slice": func(slice []string) string {
					return strings.Join(slice, " ")
				},
				"clear": func(s string) string {
					return regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(s, "")
				},
				"is_auth": func(u interface{}) bool {
					log.Printf("Is auth user: %v", u)
					if u != nil {
						user := u.(w.User)
						return user.IsAuthenticated()
					}
					return false
				},
			},
		},
	}))

	m.MapTo(db, (*d.DB)(nil))

	r := martini.NewRouter()
	r = w.EnsureAuth(r, db)

	r.Get("/klichat", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(r render.Render, req *http.Request) {
		r.HTML(200, "index", w.AddCurrentUser(map[string]interface{}{}, req, db), render.HTMLOptions{Layout: "base"})
	})

	r.Group("/profile", func(r martini.Router) {
		type ProfileId struct {
			Id string `json:"id"`
		}
		pg_conf := cfg.Main.PGDatabase
		ph, err := NewProfileDbHandler(pg_conf.ConnString, cfg.Main.ConfigDatabase)
		if err != nil {
			panic(err)
		}

		r.Get("", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render) {
			render.HTML(200, "profile", map[string]interface{}{})
		})
		r.Get("/all", func(render render.Render) {
			log.Printf("CS start querying for all profiles...")
			profiles, err := ph.GetAllProfiles()
			if err != nil {
				log.Printf("CS Error at getting all profiles: %v", err)
				render.JSON(500, map[string]interface{}{"success": false, "error": err})
			}
			log.Printf("CS found %v profiles.", len(profiles))
			render.JSON(200, map[string]interface{}{
				"success":  true,
				"profiles": profiles,
			})
		})
		r.Get("/link_types", func(render render.Render) {
			render.JSON(200, map[string]interface{}{"data": ph.GetContactLinkTypes()})
		})
		r.Post("/read", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render, params martini.Params, req *http.Request) {
			data, err := ioutil.ReadAll(req.Body)
			if err != nil {
				log.Printf("error at reading post data %v", err)
			}
			log.Printf("CS READ data: %s", data)
			info := ProfileId{}
			err = json.Unmarshal(data, &info)
			if err != nil {
				log.Printf("CS READ error at unmarshal read data %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			profile, err := ph.GetProfile(info.Id)
			if err != nil {
				log.Printf("CS READ error at unmarshal read data %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			out, err := json.Marshal(profile)
			if err != nil {
				log.Printf("CS READ error at marshal data to out")
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
			}
			render.JSON(200, map[string]interface{}{"success": true, "data": out})
		})

		r.Post("/create", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render, params martini.Params, req *http.Request) {
			data, err := ioutil.ReadAll(req.Body)
			if err != nil {
				log.Printf("error at reading post data %v", err)
			}
			log.Printf("CS CREATE data: %s", data)
			profile := &Profile{}
			err = json.Unmarshal(data, profile)
			if err != nil {
				log.Printf("CS CREATE error at unmarshal data at create profile %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			profile = ProfileTextTagClear(profile)
			log.Printf("CS CREATE profile: %+v", profile)
			profile, err = ph.InsertNewProfile(profile)
			if err != nil {
				log.Printf("CS CREATE DB are not available")
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
			}
			out, err := json.Marshal(profile)
			if err != nil {
				log.Printf("CS CREATE error at marshal data to out")
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
			}
			render.JSON(200, map[string]interface{}{"success": true, "data": out})
		})

		r.Post("/update", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render, params martini.Params, req *http.Request) {
			data, err := ioutil.ReadAll(req.Body)
			log.Printf("CS UPDATE data: %s", data)
			if err != nil {
				log.Printf("CS UPDATE error at reading post data %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			profile := &Profile{}
			err = json.Unmarshal(data, profile)
			if err != nil {
				log.Printf("CS UPDATE error at unmarshal data at create profile %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			profile = ProfileTextTagClear(profile)
			log.Printf("CS UPDATE profile: %+v", profile)
			err = ph.UpdateProfile(profile)
			if err != nil {
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			render.JSON(200, map[string]interface{}{"success": true})
		})

		r.Post("/delete", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render, params martini.Params, req *http.Request) {
			data, err := ioutil.ReadAll(req.Body)
			if err != nil {
				log.Printf("CS DELETE error at reading post data %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			log.Printf("CS DELETE data: %s", data)

			info := ProfileId{}
			err = json.Unmarshal(data, &info)
			if err != nil {
				log.Printf("CS DELETE error at unmarshal delete data %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			err = ph.DeleteProfile(info.Id)
			if err != nil {
				log.Printf("CS DELETE error at which return storage %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			render.JSON(200, map[string]interface{}{"success": true})
		})
		r.Post("/upload_img/:profile_id", func(render render.Render, params martini.Params, req *http.Request) {
			profile_id := params["profile_id"]
			path := fmt.Sprintf("%v/%v", cfg.Console.ProfileImgPath, profile_id)
			file, handler, err := req.FormFile("img_file")
			defer file.Close()
			if err != nil {
				log.Printf("CS error at forming file %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}

			if !strings.Contains(handler.Header.Get("Content-Type"), "image") {
				render.JSON(200, map[string]interface{}{"error": "Вы загружаете не картинку", "success": false})
				return
			}

			err = os.Mkdir(path, 0777)
			if err != nil {
				log.Printf("CS warn at mkdir %v", err)
			}

			profile, err := ph.GetProfile(profile_id)
			if err != nil {
				log.Printf("CS error at getting profile")
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			if profile == nil {
				profile = &Profile{UserName: profile_id}
			} else {
				splitted := strings.Split(profile.ImageURL, "/")
				savedFname := splitted[len(splitted)-1]
				err = os.Remove(filepath.Join(path, savedFname))
				if err != nil {
					log.Printf("CS Error at remove old icon ha ha ha")
				}
			}

			file_path := fmt.Sprintf("%v/%v", path, handler.Filename)
			f, err := os.OpenFile(file_path, os.O_WRONLY|os.O_CREATE, 0664)
			defer f.Close()
			if err != nil {
				log.Printf("CS error at open file %v", err)
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			log.Printf("CS will save file at: [%v]", file_path)
			io.Copy(f, file)
			file_url := fmt.Sprintf("%v/%v/%v", cfg.Console.ProfileImgServer, profile_id, handler.Filename)
			log.Printf("CS will form image at: [%v]", file_url)

			profile.ImageURL = file_url
			ph.UpdateProfile(profile)

			render.JSON(200, map[string]interface{}{"success": true, "url": file_url})
		})
		r.Get("/employee/:phone", func(render render.Render, params martini.Params, req *http.Request) {
			phone := params["phone"]
			employee, err := ph.GetEmployeeByPhone(phone)
			if err != nil {
				log.Printf("CS Error getting employee by phone")
				render.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			render.JSON(200, map[string]interface{}{"success": true, "employee": employee})
		})
		r.Get("/all_groups", func(ren render.Render) {
			log.Printf("CS start querying for all groups")
			groups, err := ph.GetAllGroups()
			if err != nil {
				log.Printf("CS error at groups retrieve: %v", err)
				ren.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			log.Printf("CS forming next groups: %+v", groups)
			ren.JSON(200, map[string]interface{}{"success": true, "groups": groups})
		})

		r.Get("/all_features", func(ren render.Render) {
			log.Printf("CS start querying for all features")
			features, err := ph.GetAllFeatures()
			if err != nil {
				log.Printf("CS error at features retrieve: %v", err)
				ren.JSON(500, map[string]interface{}{"error": err, "success": false})
				return
			}
			log.Printf("CS forming next features: %+v", features)
			ren.JSON(200, map[string]interface{}{"success": true, "features": features})
		})
	})

	r.Group("/chat", func(r martini.Router) {

		r.Get("", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(r render.Render, params martini.Params, req *http.Request) {
			var with string
			result_data := map[string]interface{}{}
			query := req.URL.Query()
			for key, value := range query {
				if key == "with" && len(value) > 0 {
					with = value[0]
					log.Printf("CONSOLE CHAT: [with] == [%v]", with)
					break
				}
			}
			if with == "" {
				with = ALL
			}
			db.Messages.SetMessagesRead(with)
			collocutor := Collocutor{}

			var messages []d.MessageWrapper
			if with != ALL {
				user, _ := db.Users.GetUserById(with)
				if user != nil {
					messages, _ = db.Messages.GetMessages(bson.M{
						"$or": []bson.M{
							bson.M{"from": user.UserId},
							bson.M{"to": user.UserId},
						},
					})
					for i, _ := range messages {
						if messages[i].From != ME {
							messages[i].From = user.UserName
						}
					}
					collocutor.Name = user.UserName
					collocutor.Phone = user.Phone
					collocutor.Email = user.Email

					order_count, _ := db.Orders.Collection.Find(bson.M{"whom": user.UserId}).Count()
					resp := []OrdersInfo{}
					err := db.Orders.Collection.Pipe([]bson.M{
						bson.M{"$match": bson.M{"whom": user.UserId}},
						bson.M{"$group": bson.M{"_id": "$source", "count": bson.M{"$sum": 1}}}}).All(&resp)

					if err == nil {
						collocutor.Info.CountOrdersByProvider = resp
					}
					collocutor.Info.CountOrdersAll = order_count
					collocutor.InfoPresent = true
				}
			}

			if strings.Contains(with, ALL) {
				messages, _ = db.Messages.GetMessages(bson.M{"to": with})
			}
			result_data["collocutor"] = collocutor
			result_data["with"] = with
			result_data["messages"] = messages

			if contacts, err := GetContacts(db); err == nil {
				result_data["contacts"] = contacts
			}
			log.Printf("CS result data :%+v", result_data)
			r.HTML(200, "chat", w.AddCurrentUser(result_data, req, db), render.HTMLOptions{Layout: "base"})
		})

		r.Post("/send", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render, req *http.Request) {
			type MessageFromF struct {
				From string `json:"from"`
				To   string `json:"to"`
				Body string `json:"body"`
			}
			data, err := ioutil.ReadAll(req.Body)
			if err != nil {
				log.Printf("CS QE E: errror at reading req body %v", err)
				render.JSON(500, map[string]interface{}{"error": err})
				return
			}
			message := MessageFromF{}
			err = json.Unmarshal(data, &message)
			if err != nil {
				log.Printf("CS QE E: at unmarshal json messages %v\ndata:%s", err, data)
				render.JSON(500, map[string]interface{}{"error": err})
				return
			}
			log.Printf("SEND MESSAGE: %+v", message)
			var messageSID string
			if message.From != "" && message.To != "" && message.Body != "" {
				if message.To == ALL {
					peoples, _ := db.Users.GetBy(bson.M{"user_id": bson.M{"$ne": message.From}})
					ntf.SendMessageToPeople(peoples, message.Body)

				} else if message.To == "all_hash_writers" {
					peoples, _ := db.Users.GetBy(bson.M{"last_marker": bson.M{"$exists": true}})
					ntf.SendMessageToPeople(peoples, message.Body)

				} else {
					user, _ := db.Users.GetUserById(message.To)
					if user != nil {
						db.Messages.SetMessagesRead(user.UserId)
						_, resultMessage, _ := ntf.NotifyText(message.To, message.Body)
						resultMessage, _ = db.Messages.GetMessageByMessageId(resultMessage.MessageID)
						messageSID = resultMessage.SID
					}
				}
				if err != nil {
					render.JSON(500, map[string]interface{}{"error": err})
				}
			} else {
				render.Redirect("/chat")
			}
			render.JSON(200, map[string]interface{}{"ok": true, "message": d.NewMessageForWeb(messageSID, message.From, message.To, message.Body)})
		})

		r.Post("/messages_read", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render, req *http.Request) {
			type Readed struct {
				From string `json:"from"`
			}
			data, err := ioutil.ReadAll(req.Body)
			if err != nil {
				log.Printf("CS QE E: errror at reading req body %v", err)
				render.JSON(500, map[string]interface{}{"error": err})
				return
			}
			readed := Readed{}
			err = json.Unmarshal(data, &readed)
			if err != nil {
				log.Printf("CS QE E: at unmarshal json messages %v\ndata:%s", err, data)
				render.JSON(500, map[string]interface{}{"error": err})
				return
			}
			err = db.Messages.SetMessagesRead(readed.From)
			if err != nil {
				log.Printf("CS QE E: at unmarshal json messages %v\ndata:%s", err, data)
				render.JSON(500, map[string]interface{}{"error": err})
				return
			}
			render.JSON(200, map[string]interface{}{"ok": true})
		})

		r.Post("/unread_messages", func(render render.Render, req *http.Request) {
			type NewMessagesReq struct {
				For   string `json:"m_for"`
				After int64  `json:"after"`
			}
			q := NewMessagesReq{}
			request_body, err := ioutil.ReadAll(req.Body)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
				return
			}
			err = json.Unmarshal(request_body, &q)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
				return
			}
			query := bson.M{"time_stamp": bson.M{"$gt": q.After}}
			if q.For == "" {
				query["to"] = ME
			} else {
				query["from"] = q.For
			}

			messages, err := db.Messages.GetMessages(query)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("error in db: %v", err)})
				return
			}
			result := []d.MessageWrapper{}
			for i, msg := range messages {
				if msg.From != ME {
					u, _ := db.Users.GetUserById(msg.From)
					if u.ShowedName != "" {
						messages[i].From = u.ShowedName
					} else {
						messages[i].From = u.UserName
					}
					result = append(result, messages[i])
				}
			}
			render.JSON(200, map[string]interface{}{"messages": result, "next_": time.Now().Unix()})
		})

		r.Post("/contacts", func(render render.Render, req *http.Request) {
			type NewContactsReq struct {
				Exist []string `json:"exist"`
			}
			cr := NewContactsReq{}
			request_body, err := ioutil.ReadAll(req.Body)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
				return
			}
			err = json.Unmarshal(request_body, &cr)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
				return
			}
			contacts, err := GetContacts(db)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("db err body %v", err)})
				return
			}
			new_contacts := []usrs.Contact{}
			old_contacts := []usrs.Contact{}

			for _, contact := range contacts {
				if u.InS(contact.ID, cr.Exist) {
					if contact.NewMessagesCount > 0 {
						old_contacts = append(old_contacts, contact)
					}
				} else {
					new_contacts = append(new_contacts, contact)
				}
			}
			render.JSON(200, map[string]interface{}{
				"ok":    true,
				"new":   new_contacts,
				"old":   old_contacts,
				"next_": time.Now().Unix(),
			})

		})
		r.Delete("/delete_messages", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(params martini.Params, ren render.Render, req *http.Request) {
			type DeleteInfo struct {
				From string `json:"from"`
				To   string `json:"to"`
			}
			data, err := ioutil.ReadAll(req.Body)
			if err != nil {
				log.Printf("CS QE E: errror at reading req body %v", err)
				ren.JSON(500, map[string]interface{}{"error": err})
				return
			}
			dInfo := DeleteInfo{}
			err = json.Unmarshal(data, &dInfo)
			if err != nil {
				log.Printf("CS QE E: at unmarshal json messages %v\ndata:%s", err, data)
				ren.JSON(500, map[string]interface{}{"error": err})
				return
			}
			count, err := db.Messages.DeleteMessages(dInfo.From, dInfo.To)
			if err != nil {
				ren.JSON(500, map[string]interface{}{"error": err})
				return
			}
			ren.JSON(200, map[string]interface{}{"success": true, "deleted": count})
		})

		r.Post("/contacts_change", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render, req *http.Request) {
			type NewContactName struct {
				Id      string `json:"id"`
				NewName string `json:"new_name"`
			}
			ncn := NewContactName{}
			request_body, err := ioutil.ReadAll(req.Body)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": "can not read request body"})
				return
			}
			err = json.Unmarshal(request_body, &ncn)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": fmt.Sprintf("can not unmarshal request body %v \n %s", err, request_body)})
				return
			}
			err = db.Users.SetUserShowedName(ncn.Id, ncn.NewName)
			if err != nil {
				render.JSON(500, map[string]interface{}{"ok": false, "detail": err})
				return
			}
			render.JSON(200, map[string]interface{}{"ok": true})
		})
	})

	r.Get("/vote_result", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(ren render.Render, req *http.Request) {
		votes, err := vdh.GetTopVotes(-1)
		if err != nil {
			log.Printf("CS ERROR at retrieving votes %v", err)
		}
		ren.HTML(200, "vote_result", w.AddCurrentUser(map[string]interface{}{"votes": votes}, req, db), render.HTMLOptions{Layout: "base"})
	})

	r = EnsureWorkWithKeys(r, qs, db)
	r = EnsureWorkWithUsers(r, db)

	r.Get("/statistic", w.LoginRequired, w.AutHandler.CheckIncludeAnyRole(MANAGER), func(render render.Render) {
		err := EnsureStatistic(filepath.Join(martini.Root, "static", "tmp"))
		if err != nil {
			log.Printf("CS ERROR at formin statistics :( ")
			render.JSON(500, map[string]interface{}{"error": err})
		}
		log.Printf("saved: %v", martini.Root)
		render.Redirect("/tmp/statistic.xlsx")
	})

	r.Get("/logout",
		w.LoginRequired,
		func(user w.User, db d.DB, ren render.Render, req *http.Request, rw http.ResponseWriter) {
			err := db.UsersStorage().LogoutUser(user.UniqueId())
			if err != nil {
				log.Printf("CONSOLE error at logout user: %v", err)
			}
			w.StopAuthSession(rw)

			ren.Redirect(w.AUTH_URL, 302)
		})
	m.Action(r.Handle)
	m.RunOnAddr(addr)
}