[Go Revel] ランダムな文字列作成

app.go

import (
	"github.com/revel/revel"
	"app/app/models"
	"fmt"
	_ "image/jpeg"
	"io/ioutil"
	"os"
	"net/smtp"
	"crypto/rand"
	"errors"
)

func (c App) Rand() revel.Result {

	random, _ := MakeRandomStr(8)
	fmt.Println(random)
	return c.Render()
}

func MakeRandomStr(digit uint32)(string, error){
	const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

	b := make([]byte, digit)
	if _, err := rand.Read(b); err != nil {
		return "", errors.New("unexpected error...")
	}

	var result string
	for _, v := range b {
		result += string(letters[int(v)%len(letters)])
	}
	return result, nil
}

dJdJvsWf

OK, これでPasswordを作成する

[Go Revel] Mailtrapによるメール送信

gmailのsmtpで送信する場合と書き方はほぼ同じ

func (c App) Mail() revel.Result {

	name := "hpscript"
	email := "test@hpscript.com"
	comments := "桜木町の夜景は良いですね"

	auth := smtp.PlainAuth (
		"",
		"hogehoge", // Mailtrap Username
		"fugafuga", // Mailtrap Password
		"smtp.mailtrap.io",
	)

	msg := []byte("From: info@hpscript.com\r\n" +
		"To: " +email + "\r\n" +
		"Subject: SMTPテスト\r\n" +
		"\r\n" +
		"名前: " + name + "\r\n" +
		"メールアドレス" + email + "\r\n" +
		"問い合わせ内容: " + comments + "\r\n")

	err := smtp.SendMail(
		"smtp.mailtrap.io:25",
		auth,
		"info@hpscrpt.com",
		[]string{email}, // 宛先
		msg,
	)

	if err != nil {
		fmt.Println(err)
	}
	return c.Render()
}

OKOK

[Go Revel] メール送信の実装方法

まずメール送信用のルートを作成

GET		/mail				  App.Mail

app.go
– net/smtpをimport
– パスワードはアプリ固有のパスワード

import (
	"github.com/revel/revel"
	"net/smtp"
)
func (c App) Mail() revel.Result {

	name := "hpscript"
	email := "test@hpscript.com"
	comments := "桜木町の夜景は良いですね"

	auth := smtp.PlainAuth (
		"",
		"myaddress@gmail.com", // gmailのアドレス
		"hogehoge", // アプリ固有のパスワード
		"smtp.gmail.com",
	)

	msg := []byte("From: info@hpscript.com\r\n" +
		"To: info@hpscript.com\r\n" +
		"Subject: SMTPテスト\r\n" +
		"\r\n" +
		"名前: " + name + "\r\n" +
		"メールアドレス" + email + "\r\n" +
		"問い合わせ内容: " + comments + "\r\n")

	err := smtp.SendMail(
		"smtp.gmail.com:587",
		auth,
		"info@hpscrpt.com",
		[]string{"fugafuga@hotmail.com"}, // 宛先
		msg,
	)

	if err != nil {
		fmt.Println(err)
	}
	return c.Render()
}

これmailtrapでも送れそうだな

[Go Revel] MySQLのuniqueなvalidationでredirect

ユーザのsigninの際に、既に同じユーザ名の登録があれば、登録できないようにしたい。

mysql側ではnameにUnique keyをつけている

mysql> describe users;
+———-+————–+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+———-+————–+——+—–+———+—————-+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | UNI | NULL | |
| email | varchar(255) | YES | | NULL | |
| password | varchar(255) | YES | | NULL | |
| filepath | varchar(255) | YES | | NULL | |
| message | text | YES | | NULL | |
+———-+————–+——+—–+———+—————-+
6 rows in set (0.01 sec)

これだと、実際に同じnameで入力があった場合、mysql側にはinsertされないが、
ページがそのまま遷移してしまう。
そのため、同じnameの入力があった場合は、入力画面に戻るようにしたい

revelでc.Validation.${} でunique判定が見当たらないので、
実際にselectして、処理する

	result := []models.Users{}
	DB.Where("name = ?", name).First(&result)


	if len(result) != 0 {
		c.Flash.Error("Same username is registered!")
		c.Validation.Keep()
		c.FlashParams()
		return c.Redirect(App.Signin)
	}
	
	hashPassword := getMD5Hash(password)
	DB.Create(&models.Users{
		Name: name,
		Email: email,
		Password: hashPassword,
	})
	
	return c.Render()

これ2時間ぐらいかかった…
go revelとか、documentなさすぎやろ😖😖😖😖

[Go Revel] Templateで else ifを使う

html
– uploadファイルがあればuploadファイル、元からセットされてらファイルがあればその画像、なければplaceholdeの画像を表示する

              {{if .filepath}}
               <img src="{{ .filepath }}" width="150px" height="150px" class="img-icon preview1">
              {{else if .set_filepath}}
              <img src="{{ .set_filepath }}" width="150px" height="150px" class="img-icon preview1">
              {{else}}
              <img src="http://placehold.jp/150x150.png" class="img-icon">
              {{end}}

普通にif, else ifで実装できますね。
controllerがそこそこ複雑になってきた。
djangoもそうだが、controllerを1ファイルでまとめると、縦に長くなるので、controllerを分けたいという欲求が少なからずある

[Go Revel] Templateで値がnilか否かで条件分岐

画像uploadの確認画面で、uploadファイルがあればその画像を表示し、なければplaceholdの画像を表示したい

app.go
– filepathを””で宣言し、uploadファイルがあれば、保存するファイルパスに置き換える

                filepath := ""
	if file1 != nil {
		fmt.Println(c.Params.Files["file1"][0].Filename)
		filename := c.Params.Files["file1"][0].Filename
		data, e := ioutil.ReadAll(file1)
		if e != nil {
			fmt.Println("error")
		}
		ioutil.WriteFile("public/tmp/" + filename, data, 777)
		filepath = "public/tmp/" + filename
	}

uploadconfirm.html
– if eq で値の中身を確認して条件分岐で表示する。 {{if .filepath == “” }}と書くとエラーになるので注意が必要

            <td>
              {{if eq .filepath ""}}
              <img src="http://placehold.jp/150x150.png" class="img-icon">
              {{ else }}
              <img src="{{ .filepath }}" width="150px" height="150px" class="img-icon preview1">
              {{end}}
              <div class=""></div>
            </td>

go本体では、if .filepath == “” という順番でかけるのに、templateでは if eq と書かなければダメなのは面白いですね。いっその事統一して欲しいですが…

[Go Revel] FileのUploadと画像の保存

test.html

<h1>テストデータのアップロードページ</h1>
    <form name="upload" method="POST" action="/test/upload" enctype="multipart/form-data">
      <input type="file"   name="imgFile"  accept="image/jpeg, image/png">
      <input type="submit" name="submit"   value="commit">
    </form>

App.go

import (
	"github.com/revel/revel"
	"app/app/models"
	"fmt"
	"os"
)

func (c App) Test() revel.Result {

	return c.Render()
}

func (c App) Upload(imgFile *os.File) revel.Result {
  fmt.Printf("imgFile => %v\n", imgFile)
  return c.Redirect(App.Test)
}

imgFile => &{0xc0000a85a0}

### 画像の保存
– ioutil.WriteFile(path, data, permission)で画像を保存する

import (
	"github.com/revel/revel"
	"app/app/models"
	"fmt"
	"io/ioutil"
	"os"
)

func (c App) Upload(imgFile *os.File) revel.Result {
  fmt.Println(c.Params.Files["imgFile"][0].Filename)
  name := c.Params.Files["imgFile"][0].Filename
  data, e := ioutil.ReadAll(imgFile)
  if e != nil {
	fmt.Println("error")
  }
  ioutil.WriteFile("public/tmp/" + name, data, 755)

  return c.Redirect(App.Test)

}

おおお、なんか久しぶりに感動した。

[Go Revel] パスワード変更のバリデーション実装方法

html
L 新しいパスワードと、パスワード確認のフォームを用意する
L radioボタンでchangeなら表示、not changeなら非表示

<tr>
            <td>Password</td>
            <td><input type="radio" name="password_change" value="n" checked>Not Change <input type="radio" name="password_change" value="y">Change
            <div class="changeterm displaynone">
              <input type="password" name="password" class="input" placeholder="new password"><br>
              <input type="password" name="password_confirm" class="input" placeholder="new password confirm">
                    </div>
            </td>
          </tr>

app.go
  L passwordが4文字以上の場合は、Min()を使う
   L if文でpasswordとpassword_confirmが一致かではなく、requiredの中で一致するか確認する

func (c App) MypageConfirm(email string, message string, password string, password_confirm string) revel.Result {

	// 省略
	if len(password) > 0 {
		c.Validation.Min(len(password), 4).Message("Password must be more than 4 character")
		c.Validation.Required(password == password_confirm).Message("password and password confirmation must be same.")
	}

	// 省略
	return c.Render(name, email, message)
}

if文で書きたいところだが、変わってるなー

[Go Revel] CSRF対策を行う

### revel-csrfをインストール
$ go get github.com/cbonello/revel-csrf

app/init.go

import (
	"github.com/revel/revel"
	"prd/app/controllers"
	"github.com/cbonello/revel-csrf" // 追加
	_ "github.com/revel/modules"

)
	revel.Filters = []revel.Filter{
		// 省略
		csrf.CSRFFilter, 			   // 追加
	}

*.html

      <form action="/mypage-confirm" method="post" enctype="multipart/form-data">
      <input type="hidden" name="csrf_token" value="{{ .csrf_token }}" />
      // 省略

CSRFがないと何か落ち着きませんが、あって良かったです。

[Go Revel] Emailのバリデーション

c.Validation.Email(email)と書く

app.go

func (c App) MypageConfirm(email string, message string) revel.Result {

	name := c.Session["userName"]
	c.Validation.Required(email).Message("Email is required")
	c.Validation.Email(email).Message("Please enter in email format")

	if c.Validation.HasErrors(){
		c.Validation.Keep()
		c.FlashParams()
		return c.Redirect(App.Mypage)
	}

	return c.Render(name, email, message)
}

うん、良さそうではある