コード例 #1
0
ファイル: chat.go プロジェクト: dzyk/dcoin-go
func (c *Controller) Chat() (string, error) {

	myChatName := utils.Int64ToStr(c.SessUserId)
	// возможно у отпарвителя есть ник
	name, err := c.Single(`SELECT name FROM users WHERE user_id = ?`, c.SessUserId).String()
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	if len(name) > 0 {
		myChatName = name
	}

	TemplateStr, err := makeTemplate("chat", "chat", &chatPage{
		Community:    c.Community,
		CountSignArr: c.CountSignArr,
		CountSign:    c.CountSign,
		Lang:         c.Lang,
		ShowSignData: c.ShowSignData,
		SignData:     "",
		MyChatName:   myChatName,
		UserId:       c.SessUserId,
		IOS:          utils.IOS(),
		Mobile:       utils.Mobile()})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
コード例 #2
0
ファイル: set_password.go プロジェクト: dzyk/dcoin-go
func (c *Controller) SetPassword() (string, error) {

	TemplateStr, err := makeTemplate("set_password", "setPassword", &setPasswordPage{
		Lang: c.Lang, IOS: utils.IOS(), Android: utils.Android(), Mobile: utils.Mobile()})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
コード例 #3
0
ファイル: upgrade_1.go プロジェクト: dzyk/dcoin-go
func (c *Controller) Upgrade1() (string, error) {

	log.Debug("Upgrade1")

	userFace := ""
	/*userProfile := ""

	path := "public/"+utils.Int64ToStr(c.SessUserId)+"_user_profile.jpg"
	if _, err := os.Stat(path); err == nil {
		userProfile = path
	}*/

	path := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg"
	if _, err := os.Stat(path); err == nil {
		userFace = "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg"
	}

	step := "1"
	nextStep := "2"
	photoType := "face"
	photo := userFace

	saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "3", -1)
	upgradeMenu := utils.MakeUpgradeMenu(1)

	TemplateStr, err := makeTemplate("upgrade_1_and_2", "upgrade1And2", &upgrade1Page{
		Alert:           c.Alert,
		Lang:            c.Lang,
		CountSignArr:    c.CountSignArr,
		ShowSignData:    c.ShowSignData,
		SaveAndGotoStep: saveAndGotoStep,
		UpgradeMenu:     upgradeMenu,
		UserId:          c.SessUserId,
		PhotoType:       photoType,
		Photo:           photo,
		Step:            step,
		NextStep:        nextStep,
		IOS:             utils.IOS(),
		Mobile:          utils.Mobile()})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
コード例 #4
0
ファイル: index.go プロジェクト: dzyk/dcoin-go
func Index(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()

	parameters_ := make(map[string]interface{})
	err := json.Unmarshal([]byte(r.PostFormValue("parameters")), &parameters_)
	if err != nil {
		log.Error("%v", err)
	}
	log.Debug("parameters_=%", parameters_)
	parameters := make(map[string]string)
	for k, v := range parameters_ {
		parameters[k] = utils.InterfaceToStr(v)
	}

	lang := GetLang(w, r, parameters)

	sess, err := globalSessions.SessionStart(w, r)
	if err != nil {
		log.Error("%v", err)
	}
	defer sess.SessionRelease(w)

	sessUserId := GetSessUserId(sess)

	var key, myPrefix, status string
	var communityUsers []int64
	var chatEnabled, analyticsDisabled string
	if utils.DB != nil && utils.DB.DB != nil {
		communityUsers, err = utils.DB.GetCommunityUsers()
		if err != nil {
			log.Error("%v", err)
		}
		if len(communityUsers) > 0 {
			myPrefix = utils.Int64ToStr(sessUserId) + "_"
		}
		status, err := utils.DB.Single("SELECT status FROM " + myPrefix + "my_table").String()

		// чтобы нельзя было зайти по локалке
		// :: - для маков
		if ok, _ := regexp.MatchString(`(\:\:)|(127\.0\.0\.1)`, r.RemoteAddr); ok {
			if status != "waiting_accept_new_key" && status != "waiting_set_new_key" {
				key, err = utils.DB.Single("SELECT private_key FROM " + myPrefix + "my_keys WHERE block_id = (SELECT max(block_id) FROM " + myPrefix + "my_keys)").String()
				if err != nil {
					log.Error("%v", err)
				}
			}
		}
		chatEnabled, err = utils.DB.Single(`SELECT chat_enabled FROM config`).String()
		if err != nil {
			log.Error("%v", err)
		}
		analyticsDisabled, err = utils.DB.Single(`SELECT analytics_disabled FROM config`).String()
		if err != nil {
			log.Error("%v", err)
		}
	}

	showIOSMenu := true
	// Когда меню не выдаем
	if utils.DB == nil || utils.DB.DB == nil {
		showIOSMenu = false
	} else {
		if status == "my_pending" {
			showIOSMenu = false
		}
	}

	if sessUserId == 0 {
		showIOSMenu = false
	}

	if showIOSMenu && utils.DB != nil && utils.DB.DB != nil {
		blockData, err := utils.DB.GetInfoBlock()
		if err != nil {
			log.Error("%v", err)
		}
		wTime := int64(12)
		wTimeReady := int64(2)
		log.Debug("wTime: %v / utils.Time(): %v / blockData[time]: %v", wTime, utils.Time(), utils.StrToInt64(blockData["time"]))
		// если время менее 12 часов от текущего, то выдаем не подвержденные, а просто те, что есть в блокчейне
		if utils.Time()-utils.StrToInt64(blockData["time"]) < 3600*wTime {
			lastBlockData, err := utils.DB.GetLastBlockData()
			if err != nil {
				log.Error("%v", err)
			}
			log.Debug("lastBlockData[lastBlockTime]: %v", lastBlockData["lastBlockTime"])
			log.Debug("time.Now().Unix(): %v", utils.Time())
			if utils.Time()-lastBlockData["lastBlockTime"] >= 3600*wTimeReady {
				showIOSMenu = false
			}
		} else {
			showIOSMenu = false
		}
	}
	if showIOSMenu && !utils.Mobile() {
		showIOSMenu = false
	}

	mobile := utils.Mobile()
	if ok, _ := regexp.MatchString("(?i)(iPod|iPhone|iPad|Android)", r.UserAgent()); ok {
		mobile = true
	}

	ios := utils.IOS()
	if ok, _ := regexp.MatchString("(?i)(iPod|iPhone|iPad)", r.UserAgent()); ok {
		ios = true
	}

	android := utils.Android()
	if ok, _ := regexp.MatchString("(?i)(Android)", r.UserAgent()); ok {
		android = true
	}

	var upgrade3 string
	if len(r.FormValue("upgrade3")) > 0 {
		upgrade3 = "1"
	}
	var upgrade4 string
	if len(r.FormValue("upgrade4")) > 0 {
		upgrade4 = "1"
	}
	formKey := r.FormValue("key")
	if len(formKey) > 0 {
		key = formKey
		// пишем в сессию, что бы ctrl+F5 не сбрасывал ключ (для авто-входа с dcoin.club)
		sess.Set("private_key", key)
	} else if len(key) == 0 {
		key = GetSessPrivateKey(w, r)
	}
	key = strings.Replace(key, "\r", "\n", -1)
	key = strings.Replace(key, "\n\n", "\n", -1)
	key = strings.Replace(key, "\n", "\\\n", -1)

	setLang := r.FormValue("lang")

	data, err := static.Asset("static/templates/index.html")
	t := template.New("template")
	t, err = t.Parse(string(data))
	if err != nil {
		log.Error("%v", err)
	}
	b := new(bytes.Buffer)
	err = t.Execute(b, &index{
		Upgrade3:    upgrade3,
		Upgrade4:    upgrade4,
		DbOk:        true,
		Lang:        globalLangReadOnly[lang],
		Key:         key,
		SetLang:     setLang,
		ShowIOSMenu: showIOSMenu,
		/*IOS: true,
		Android: false,
		Mobile: true})*/
		IOS:               ios,
		Android:           android,
		ChatEnabled:       chatEnabled,
		AnalyticsDisabled: analyticsDisabled,
		Mobile:            mobile})
	if err != nil {
		log.Error("%v", err)
	}
	w.Write(b.Bytes())
}
コード例 #5
0
ファイル: home.go プロジェクト: dzyk/dcoin-go
func (c *Controller) Home() (string, error) {

	log.Debug("first_select: %v", c.Parameters["first_select"])
	if c.Parameters["first_select"] == "1" {
		c.ExecSql(`UPDATE ` + c.MyPrefix + `my_table SET first_select=1`)
	}

	var publicKey []byte
	var poolAdmin bool
	var cashRequests int64
	var showMap bool
	if c.SessRestricted == 0 {
		var err error
		publicKey, err = c.GetMyPublicKey(c.MyPrefix)
		if err != nil {
			return "", err
		}
		publicKey = utils.BinToHex(publicKey)
		cashRequests, err = c.Single("SELECT count(id) FROM cash_requests WHERE to_user_id  =  ? AND status  =  'pending' AND for_repaid_del_block_id  =  0 AND del_block_id  =  0 and time > ?", c.SessUserId, utils.Time()-c.Variables.Int64["cash_request_time"]).Int64()
		fmt.Println("cashRequests", cashRequests)
		if err != nil {
			return "", err
		}
		show, err := c.Single("SELECT show_map FROM " + c.MyPrefix + "my_table").Int64()
		if err != nil {
			return "", err
		}
		if show > 0 {
			showMap = true
		}
	}
	if c.Community {
		poolAdminUserId, err := c.GetPoolAdminUserId()
		if err != nil {
			return "", err
		}
		if c.SessUserId == poolAdminUserId {
			poolAdmin = true
		}
	}

	wallets, err := c.GetBalances(c.SessUserId)
	if err != nil {
		return "", err
	}
	//var walletsByCurrency map[string]map[string]string
	walletsByCurrency := make(map[int]utils.DCAmounts)
	for _, data := range wallets {
		walletsByCurrency[int(data.CurrencyId)] = data
	}
	blockId, err := c.GetBlockId()
	if err != nil {
		return "", err
	}
	confirmedBlockId, err := c.GetConfirmedBlockId()
	if err != nil {
		return "", err
	}
	currencyList, err := c.GetCurrencyList(true)
	if err != nil {
		return "", err
	}
	for k, v := range currencyList {
		currencyList[k] = "d" + v
	}
	currencyList[1001] = "USD"

	// задания
	var assignments int64
	count, err := c.Single("SELECT count(id) FROM votes_miners WHERE votes_end  =  0 AND type  =  'user_voting'").Int64()
	if err != nil {
		return "", err
	}
	assignments += count

	// вначале получим ID валют, которые мы можем проверять.
	currencyIds, err := c.GetList("SELECT currency_id FROM promised_amount WHERE status IN ('mining', 'repaid') AND user_id  =  ?", c.SessUserId).String()
	if len(currencyIds) > 0 || c.SessUserId == 1 {
		addSql := ""
		if c.SessUserId == 1 {
			addSql = ""
		} else {
			addSql = "AND currency_id IN (" + strings.Join(currencyIds, ",") + ")"
		}
		count, err := c.Single("SELECT count(id) FROM promised_amount WHERE status  =  'pending' AND del_block_id  =  0 " + addSql).Int64()
		if err != nil {
			return "", err
		}
		assignments += count
	}

	if c.SessRestricted == 0 {
		count, err := c.Single("SELECT count(id) FROM "+c.MyPrefix+"my_tasks WHERE time > ?", time.Now().Unix()-consts.ASSIGN_TIME).Int64()
		if err != nil {
			return "", err
		}
		assignments -= count
		if assignments < 0 {
			assignments = 0
		}
	}

	// баллы
	points, err := c.Single("SELECT points FROM points WHERE user_id  =  ?", c.SessUserId).Int64()
	if err != nil {
		return "", err
	}

	currency_pct := make(map[int]CurrencyPct)
	// проценты
	listPct, err := c.GetMap("SELECT * FROM currency", "id", "name")
	for id, name := range listPct {
		pct, err := c.OneRow("SELECT * FROM pct WHERE currency_id  =  ? ORDER BY block_id DESC", id).Float64()
		if err != nil {
			return "", err
		}
		currency_pct[utils.StrToInt(id)] = CurrencyPct{Name: name, Miner: (utils.Round((math.Pow(1+pct["miner"], 3600*24*365)-1)*100, 2)), User: (utils.Round((math.Pow(1+pct["user"], 3600*24*365)-1)*100, 2)), MinerBlock: (utils.Round((math.Pow(1+pct["miner"], 120)-1)*100, 4)), UserBlock: (utils.Round((math.Pow(1+pct["user"], 120)-1)*100, 4)), MinerSec: (pct["miner"]), UserSec: (pct["user"])}
	}
	// случайне майнеры для нанесения на карту
	maxMinerId, err := c.Single("SELECT max(miner_id) FROM miners_data").Int64()
	if err != nil {
		return "", err
	}
	randMiners, err := c.GetList("SELECT user_id FROM miners_data WHERE status  =  'miner' AND user_id > 7 AND user_id != 106 AND longitude > 0 AND miner_id IN (" + strings.Join(utils.RandSlice(1, maxMinerId, 3), ",") + ") LIMIT 3").Int64()
	if err != nil {
		return "", err
	}

	// получаем кол-во DC на кошельках
	sumWallets_, err := c.GetMap("SELECT currency_id, sum(amount) as sum_amount FROM wallets GROUP BY currency_id", "currency_id", "sum_amount")
	if err != nil {
		return "", err
	}
	sumWallets := make(map[int]float64)
	for currencyId, amount := range sumWallets_ {
		sumWallets[utils.StrToInt(currencyId)] = utils.StrToFloat64(amount)
	}

	// получаем кол-во TDC на обещанных суммах, плюсуем к тому, что на кошельках
	sumTdc, err := c.GetMap("SELECT currency_id, sum(tdc_amount) as sum_amount FROM promised_amount GROUP BY currency_id", "currency_id", "sum_amount")
	if err != nil {
		return "", err
	}

	for currencyId, amount := range sumTdc {
		currencyIdInt := utils.StrToInt(currencyId)
		if sumWallets[currencyIdInt] == 0 {
			sumWallets[currencyIdInt] = utils.StrToFloat64(amount)
		} else {
			sumWallets[currencyIdInt] += utils.StrToFloat64(amount)
		}
	}

	// получаем суммы обещанных сумм
	sumPromisedAmount, err := c.GetMap("SELECT currency_id, sum(amount) as sum_amount FROM promised_amount WHERE status = 'mining' AND del_block_id = 0 AND (cash_request_out_time = 0 OR cash_request_out_time > ?) GROUP BY currency_id", "currency_id", "sum_amount", time.Now().Unix()-c.Variables.Int64["cash_request_time"])
	if err != nil {
		return "", err
	}

	_, _, promisedAmountListGen, err := c.GetPromisedAmounts(c.SessUserId, c.Variables.Int64["cash_request_time"])

	calcTotal := utils.Round(100*math.Pow(1+currency_pct[72].MinerSec, 3600*24*30)-100, 0)

	// токен для запроса инфы с биржи
	var token, exchangeUrl string
	if c.SessRestricted == 0 {
		tokenAndUrl, err := c.OneRow(`SELECT token, e_host FROM ` + c.MyPrefix + `my_tokens LEFT JOIN miners_data ON miners_data.user_id = e_owner_id ORDER BY time DESC LIMIT 1`).String()
		if err != nil {
			return "", err
		}
		token = tokenAndUrl["token"]
		exchangeUrl = tokenAndUrl["e_host"]
	}

	myChatName := utils.Int64ToStr(c.SessUserId)
	// возможно у отпарвителя есть ник
	name, err := c.Single(`SELECT name FROM users WHERE user_id = ?`, c.SessUserId).String()
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	if len(name) > 0 {
		myChatName = name
	}

	// получим топ 5 бирж
	topExMap := make(map[int64]*topEx)
	var q string
	if c.ConfigIni["db_type"] == "postgresql" {
		//q = "SELECT DISTINCT e_owner_id, e_host, count(votes_exchange.user_id), result from votes_exchange LEFT JOIN miners_data ON votes_exchange.e_owner_id = miners_data.user_id WHERE e_host != '' GROUP BY e_owner_id, result, e_host"
		q = "SELECT DISTINCT e_owner_id, e_host, count(votes_exchange.user_id), result from miners_data  LEFT JOIN votes_exchange ON votes_exchange.e_owner_id = miners_data.user_id WHERE e_host != '' AND result >= 0 GROUP BY e_owner_id, result, e_host"
	} else {
		//q = "SELECT e_owner_id, e_host, count(votes_exchange.user_id) as count, result FROM miners_data LEFT JOIN votes_exchange ON votes_exchange.e_owner_id = miners_data.user_id WHERE and e_host != '' GROUP BY votes_exchange.e_owner_id, votes_exchange.result LIMIT 10"
		q = "SELECT e_owner_id, e_host, count(votes_exchange.user_id) as count, result FROM miners_data LEFT JOIN votes_exchange ON votes_exchange.e_owner_id = miners_data.user_id WHERE e_host != '' AND result >= 0 GROUP BY votes_exchange.e_owner_id, votes_exchange.result LIMIT 10"
	}
	rows, err := c.Query(q)
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	defer rows.Close()
	for rows.Next() {
		var user_id, count, result int64
		var e_host []byte
		err = rows.Scan(&user_id, &e_host, &count, &result)
		if err != nil {
			return "", utils.ErrInfo(err)
		}
		if topExMap[user_id] == nil {
			topExMap[user_id] = new(topEx)
		}
		//if len(topExMap[user_id].Host) == 0 {
		//	topExMap[user_id] = new(topEx)
		if result == 0 {
			topExMap[user_id].Vote1 = count
		} else {
			topExMap[user_id].Vote1 = count
		}
		topExMap[user_id].Host = string(e_host)
		topExMap[user_id].UserId = user_id
		//}
	}

	// майнер ли я?
	miner_, err := c.Single(`SELECT miner_id FROM miners_data WHERE user_id = ?`, c.SessUserId).Int64()
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	var miner bool
	if miner_ > 0 {
		miner = true
	}

	TemplateStr, err := makeTemplate("home", "home", &homePage{
		Community:             c.Community,
		CountSignArr:          c.CountSignArr,
		CountSign:             c.CountSign,
		CalcTotal:             calcTotal,
		Admin:                 c.Admin,
		CurrencyPct:           currency_pct,
		SumWallets:            sumWallets,
		Wallets:               walletsByCurrency,
		PromisedAmountListGen: promisedAmountListGen,
		SessRestricted:        c.SessRestricted,
		SumPromisedAmount:     sumPromisedAmount,
		RandMiners:            randMiners,
		Points:                points,
		Assignments:           assignments,
		CurrencyList:          currencyList,
		ConfirmedBlockId:      confirmedBlockId,
		CashRequests:          cashRequests,
		ShowMap:               showMap,
		BlockId:               blockId,
		UserId:                c.SessUserId,
		PoolAdmin:             poolAdmin,
		Alert:                 c.Alert,
		MyNotice:              c.MyNotice,
		Lang:                  c.Lang,
		Title:                 c.Lang["geolocation"],
		ShowSignData:          c.ShowSignData,
		SignData:              "",
		MyChatName:            myChatName,
		IOS:                   utils.IOS(),
		Mobile:                utils.Mobile(),
		TopExMap:              topExMap,
		ChatEnabled:           c.NodeConfig["chat_enabled"],
		Miner:                 miner,
		Token:                 token,
		ExchangeUrl:           exchangeUrl})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
コード例 #6
0
ファイル: ios.go プロジェクト: dzyk/dcoin-go
func IosLog(text string) {
	if utils.IOS() {
		C.logNS(C.CString(text))
	}
}
コード例 #7
0
ファイル: change_primary_key.go プロジェクト: dzyk/dcoin-go
func (c *Controller) ChangePrimaryKey() (string, error) {

	var err error

	txType := "ChangePrimaryKey"
	txTypeId := utils.TypeInt(txType)
	timeNow := utils.Time()

	var myKeys []map[string]string
	if c.SessRestricted == 0 {
		myKeys, err = c.GetAll(`SELECT * FROM `+c.MyPrefix+`my_keys ORDER BY id DESC`, -1)
	}

	statusArray := map[string]string{"my_pending": c.Lang["local_pending"], "approved": c.Lang["status_approved"]}

	// узнаем, когда последний раз была смена ключа, чтобы не показывать юзеру страницу смены
	lastChangeKeyTime, err := c.Single("SELECT time FROM log_time_primary_key WHERE user_id  =  ? ORDER BY time DESC", c.SessUserId).Int64()
	if err != nil {
		return "", utils.ErrInfo(err)
	}

	limitsText := strings.Replace(c.Lang["change_primary_key_limits_text"], "[limit]", utils.Int64ToStr(c.Variables.Int64["limit_primary_key"]), -1)
	limitsText = strings.Replace(limitsText, "[period]", c.Periods[c.Variables.Int64["limit_primary_key_period"]], -1)

	var lastTxQueueTx, lastTxTx bool
	lastTx, err := c.GetLastTx(c.SessUserId, utils.TypesToIds([]string{"ChangePrimaryKey"}), 1, c.TimeFormat)
	lastTxFormatted := ""
	if len(lastTx) > 0 {
		lastTxFormatted, _ = utils.MakeLastTx(lastTx, c.Lang)
		if len(lastTx[0]["queue_tx"]) > 0 {
			lastTxQueueTx = true
		}
		if len(lastTx[0]["tx"]) > 0 {
			lastTxTx = true
		}
	}

	TemplateStr, err := makeTemplate("change_primary_key", "changePrimaryKey", &changePrimaryKeyPage{
		Alert:             c.Alert,
		Lang:              c.Lang,
		ShowSignData:      c.ShowSignData,
		SignData:          "",
		UserId:            c.SessUserId,
		CountSignArr:      c.CountSignArr,
		LimitsText:        limitsText,
		LastTxQueueTx:     lastTxQueueTx,
		LastTxTx:          lastTxTx,
		LastTxFormatted:   lastTxFormatted,
		LastChangeKeyTime: lastChangeKeyTime,
		LastTx:            lastTx,
		MyKeys:            myKeys,
		StatusArray:       statusArray,
		TimeNow:           timeNow,
		TxType:            txType,
		IOS:               utils.IOS(),
		Android:           utils.Android(),
		Mobile:            utils.Mobile(),
		TxTypeId:          txTypeId})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}
コード例 #8
0
ファイル: upgrade_3.go プロジェクト: dzyk/dcoin-go
func (c *Controller) Upgrade3() (string, error) {

	log.Debug("Upgrade3")

	userProfile := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg"
	userFace := *utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg"

	if _, err := os.Stat(userProfile); os.IsNotExist(err) {
		userProfile = ""
	} else {
		userProfile = "public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg?r=" + utils.IntToStr(utils.RandInt(0, 99999))
	}
	if _, err := os.Stat(userFace); os.IsNotExist(err) {
		userFace = ""
	} else {
		userFace = "public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg?r=" + utils.IntToStr(utils.RandInt(0, 99999))
	}

	log.Debug("userProfile: %s", userProfile)
	log.Debug("userFace: %s", userFace)

	// текущий набор точек для шаблонов
	examplePoints, err := c.GetPoints(c.Lang)
	if err != nil {
		return "", utils.ErrInfo(err)
	}

	// точки, которые юзер уже отмечал
	data, err := c.OneRow("SELECT face_coords, profile_coords FROM " + c.MyPrefix + "my_table").String()
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	faceCoords := ""
	profileCoords := ""
	if len(data["face_coords"]) > 0 {
		faceCoords = data["face_coords"]
		profileCoords = data["profile_coords"]
	}

	saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "5", -1)
	upgradeMenu := utils.MakeUpgradeMenu(3)

	TemplateStr, err := makeTemplate("upgrade_3", "upgrade3", &upgrade3Page{
		Alert:           c.Alert,
		Lang:            c.Lang,
		CountSignArr:    c.CountSignArr,
		ShowSignData:    c.ShowSignData,
		SaveAndGotoStep: saveAndGotoStep,
		UpgradeMenu:     upgradeMenu,
		UserId:          c.SessUserId,
		FaceCoords:      faceCoords,
		ProfileCoords:   profileCoords,
		UserProfile:     userProfile,
		UserFace:        userFace,
		ExamplePoints:   examplePoints,
		IOS:             utils.IOS(),
		Mobile:          utils.Mobile()})
	if err != nil {
		return "", utils.ErrInfo(err)
	}
	return TemplateStr, nil
}