Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12995] ファイルの概要

このコミットは、misc/dashboard/codereview/dashboard/front.go ファイルに対する変更です。このファイルは、Goプロジェクトのコードレビューダッシュボードのフロントエンド(ユーザーインターフェース)を生成するGo言語のコードの一部であると推測されます。具体的には、ユーザーがダッシュボードにアクセスした際に表示されるメインページ(フロントページ)のデータ準備とHTMLレンダリングを担当しています。

コミット

このコミットは、Go言語のコードレビューダッシュボードに、現在のユーザーのメールアドレス表示と、便利なログアウトURLを追加するものです。これにより、ユーザーは自分がどのユーザーとしてログインしているかを確認でき、簡単にログアウトできるようになります。

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/5d331964e7dc9a4862ce080e6f494bcd7931fa22

元コミット内容

misc/dashboard/codereview: add handy logout URL.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6135052

変更の背景

この変更の背景には、ユーザーエクスペリエンスの向上が挙げられます。コードレビューダッシュボードは、Goプロジェクトのコントリビューターがコードレビューの状況を把握するために利用するツールです。このようなツールでは、現在ログインしているユーザーが誰であるかを明確に表示し、セッション管理の一環として簡単にログアウトできる機能を提供することが重要です。

以前のバージョンでは、ユーザーがログイン状態を確認したり、ログアウトしたりするための明確なUI要素がなかった可能性があります。このコミットは、Google App Engine (GAE) のユーザーサービスを活用して、現在のユーザーのメールアドレスを表示し、GAEが提供するログアウトURLを埋め込むことで、この不足を解消し、ダッシュボードの利便性を高めることを目的としています。

前提知識の解説

このコミットを理解するためには、以下の技術的背景知識が役立ちます。

Go言語

Go(Golang)は、Googleによって開発されたオープンソースのプログラミング言語です。シンプルさ、効率性、並行処理のサポートを重視しており、Webサービスや分散システム、CLIツールなどの開発に広く利用されています。このコードレビューダッシュボードもGo言語で書かれています。

Google App Engine (GAE)

Google App Engineは、Googleが提供するPlatform as a Service (PaaS) です。開発者はインフラストラクチャの管理を気にすることなく、スケーラブルなWebアプリケーションやバックエンドサービスを構築・デプロイできます。GAEは、ユーザー認証、データストア、タスクキューなど、多くの組み込みサービスを提供しており、このコミットでは特に「Users API」が利用されています。

GAE Users API

GAE Users APIは、アプリケーションがGoogleアカウントを持つユーザーを認証し、その情報を取得するためのサービスです。主な機能として以下があります。

  • ユーザーの認証状態の確認: ユーザーがログインしているか、匿名ユーザーか。
  • 現在のユーザー情報の取得: ログインしているユーザーのメールアドレスやIDなど。
  • ログイン/ログアウトURLの生成: アプリケーションからユーザーをGoogleのログイン/ログアウトページにリダイレクトするためのURLを動的に生成します。これにより、開発者は認証フローを自分で実装する必要がなくなります。

このコミットでは、user.Current(c).Email で現在のユーザーのメールアドレスを取得し、user.LogoutURL(c, "/") でログアウトURLを生成しています。

net/httpパッケージ (Go)

Go言語の標準ライブラリである net/http パッケージは、HTTPクライアントとサーバーの実装を提供します。Webアプリケーションのハンドラ関数(handleFrontなど)は、このパッケージの http.ResponseWriter*http.Request を引数として受け取り、HTTPリクエストの処理とレスポンスの生成を行います。

html/templateパッケージ (Go)

Go言語の html/template パッケージは、HTML出力の生成を安全に行うためのテンプレートエンジンです。クロスサイトスクリプティング(XSS)攻撃を防ぐための自動エスケープ機能が組み込まれています。このコミットでは、frontPage.ExecuteTemplate を使用して、Goのデータ構造(frontPageData)をHTMLテンプレートにバインドし、最終的なHTMLページを生成しています。テンプレート内で {{.User}}{{.LogoutURL}} のように記述することで、Goの構造体のフィールドにアクセスし、その値を表示できます。

技術的詳細

このコミットの技術的な変更点は、主に以下の3つの側面から構成されています。

  1. データ構造の拡張: frontPageData 構造体に、現在のユーザーのメールアドレスを保持する User フィールドと、ログアウトURLを保持する LogoutURL フィールドが追加されました。これらはどちらも string 型です。

    type frontPageData struct {
        // ... 既存のフィールド ...
        Reviewers      []string
        UserIsReviewer bool
        User, LogoutURL string // 新しく追加されたフィールド
    }
    
  2. ユーザー情報とログアウトURLの取得: handleFront 関数内で、Google App EngineのUsers APIを利用して、現在のユーザーのメールアドレスとログアウトURLを取得し、frontPageData インスタンスに設定しています。

    • data.User = user.Current(c).Email: user.Current(c) は現在のユーザー情報を取得し、その Email フィールドを data.User に代入しています。
    • currentPerson, data.UserIsReviewer = emailToPerson[data.User]: 以前は emailToPerson[user.Current(c).Email] と直接アクセスしていましたが、data.User に格納された値を使用するように変更され、コードの重複が解消されています。
    • data.LogoutURL, err = user.LogoutURL(c, "/"): user.LogoutURL(c, "/") は、ログアウト後にルートパス (/) にリダイレクトするためのURLを生成し、data.LogoutURL に代入しています。この処理は、既存の tableFetch というヘルパー関数(本来はテーブルデータをフェッチするためのものだが、ここではコンテキスト c を利用して非同期的にURLを取得する便宜的なラッパーとして使用されている)の中で実行されています。コメント // Not really a table fetch. がその意図を示しています。
  3. HTMLテンプレートの更新: frontPage テンプレートの <address> タグ内に、現在のユーザーのメールアドレスとログアウトリンクが表示されるように変更されました。

    <address>
    You are <span class="email">{{.User}}</span> &middot; <a href="{{.LogoutURL}}">logout</a><br />
    datastore timing: {{range .Timing}} {{.}}{{end}}
    </address>
    
    • {{.User}}: frontPageData 構造体の User フィールドの値(ユーザーのメールアドレス)が表示されます。
    • {{.LogoutURL}}: frontPageData 構造体の LogoutURL フィールドの値(ログアウトURL)が <a> タグの href 属性に設定され、クリック可能なログアウトリンクが生成されます。

また、frontPage.ExecuteTemplate(&b, "front", data)frontPage.ExecuteTemplate(&b, "front", &data) に変更されています。これは、テンプレートに渡すデータの型を値渡しからポインタ渡しに変更したことを意味します。Goのテンプレートエンジンは通常、ポインタを受け取ることで、テンプレート内でデータ構造のフィールドにアクセスしたり、場合によっては変更したりする際に効率的になります。

コアとなるコードの変更箇所

diff --git a/misc/dashboard/codereview/dashboard/front.go b/misc/dashboard/codereview/dashboard/front.go
index 20605cb164..9eb36f3143 100644
--- a/misc/dashboard/codereview/dashboard/front.go
+++ b/misc/dashboard/codereview/dashboard/front.go
@@ -25,9 +25,10 @@ func handleFront(w http.ResponseWriter, r *http.Request) {
 
 	data := &frontPageData{
 		Reviewers: personList,
+		User:      user.Current(c).Email,
 	}
 	var currentPerson string
-	currentPerson, data.UserIsReviewer = emailToPerson[user.Current(c).Email]
+	currentPerson, data.UserIsReviewer = emailToPerson[data.User]
 
 	var wg sync.WaitGroup
 	errc := make(chan error, 10)
@@ -96,6 +97,13 @@ func handleFront(w http.ResponseWriter, r *http.Request) {
 		return err
 	})
 
+	// Not really a table fetch.
+	tableFetch(0, func(_ *clTable) error {
+		var err error
+		data.LogoutURL, err = user.LogoutURL(c, "/")
+		return err
+	})
+
 	wg.Wait()
 
 	select {
@@ -107,7 +115,7 @@ func handleFront(w http.ResponseWriter, r *http.Request) {
 	}
 
 	var b bytes.Buffer
-	if err := frontPage.ExecuteTemplate(&b, "front", data); err != nil {
+	if err := frontPage.ExecuteTemplate(&b, "front", &data); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
@@ -121,6 +129,8 @@ type frontPageData struct {\n 
 	Reviewers      []string
 	UserIsReviewer bool
+
+	User, LogoutURL string
 }\n 
 type clTable struct {\n 
@@ -240,6 +250,7 @@ var frontPage = template.Must(template.New("front").Funcs(template.FuncMap{\n 
 <hr />
 <address>\n
+You are <span class="email">{{.User}}</span> &middot; <a href="{{.LogoutURL}}">logout</a><br />\n
 datastore timing: {{range .Timing}} {{.}}{{end}}\n
 </address>\n
 

コアとなるコードの解説

上記の差分は、以下の主要な変更を示しています。

  1. frontPageData 構造体の初期化とユーザーメールの取得:

    -	data := &frontPageData{
    -		Reviewers: personList,
    -	}
    +	data := &frontPageData{
    +		Reviewers: personList,
    +		User:      user.Current(c).Email,
    +	}
    

    frontPageData 構造体の初期化時に、User フィールドが追加され、user.Current(c).Email を呼び出して現在のユーザーのメールアドレスが直接代入されるようになりました。これにより、テンプレートでユーザーのメールアドレスを表示するためのデータが準備されます。

  2. ユーザーメールの参照の変更:

    -	currentPerson, data.UserIsReviewer = emailToPerson[user.Current(c).Email]
    +	currentPerson, data.UserIsReviewer = emailToPerson[data.User]
    

    emailToPerson マップからユーザー情報を取得する際に、以前は再度 user.Current(c).Email を呼び出していましたが、すでに data.User に格納されている値を使用するように変更されました。これは冗長な呼び出しを避け、コードの整合性を高めるための小さなリファクタリングです。

  3. ログアウトURLの取得:

    +	// Not really a table fetch.
    +	tableFetch(0, func(_ *clTable) error {
    +		var err error
    +		data.LogoutURL, err = user.LogoutURL(c, "/")
    +		return err
    +	})
    

    tableFetch という既存のヘルパー関数を利用して、ログアウトURLを取得しています。この関数は、appengine.Context (c) を必要とする処理を非同期的に実行するためのラッパーとして使われています。user.LogoutURL(c, "/") は、Google App EngineのUsers APIが提供する機能で、ログアウト後に指定されたパス(ここではルートパス /)にリダイレクトするURLを生成します。このURLは data.LogoutURL に格納されます。

  4. テンプレートへのデータ渡し方の変更:

    -	if err := frontPage.ExecuteTemplate(&b, "front", data); err != nil {
    +	if err := frontPage.ExecuteTemplate(&b, "front", &data); err != nil {
    

    frontPage.ExecuteTemplate 関数に渡す data 変数が、値渡し (data) からポインタ渡し (&data) に変更されました。これにより、テンプレートエンジンが frontPageData 構造体の内容にアクセスする際の挙動がより一貫性を持つようになります。

  5. frontPageData 構造体の定義変更:

    type frontPageData struct {
    	// ...
    	Reviewers      []string
    	UserIsReviewer bool
    +
    +	User, LogoutURL string
    }
    

    frontPageData 構造体に、UserLogoutURL という2つの新しい文字列型フィールドが追加されました。これらはそれぞれ、現在のユーザーのメールアドレスとログアウトURLを保持するために使用されます。

  6. HTMLテンプレートの変更:

    <hr />
    <address>
    +You are <span class="email">{{.User}}</span> &middot; <a href="{{.LogoutURL}}">logout</a><br />
    datastore timing: {{range .Timing}} {{.}}{{end}}
    </address>
    

    HTMLテンプレートの <address> セクションに、新しい行が追加されました。この行は「You are [ユーザーのメールアドレス][ログアウトリンク]」という形式で表示されます。

    • <span class="email">{{.User}}</span>: frontPageDataUser フィールドの値(ユーザーのメールアドレス)が <span> タグで囲まれて表示されます。
    • <a href="{{.LogoutURL}}">logout</a>: frontPageDataLogoutURL フィールドの値が <a> タグの href 属性に設定され、「logout」というテキストを持つクリック可能なリンクが生成されます。

これらの変更により、コードレビューダッシュボードのフロントページに、ログイン中のユーザー情報とログアウト機能が追加され、ユーザーの利便性が向上しました。

関連リンク

参考にした情報源リンク