GAS (Google App Script) で WEBサイトを公開する
この記事では、GAS (Google App Script) で WEBサイトを公開する方法を紹介する。
HelloWorldを表示する
- GASを用意する

- コード.gsにdoGet関数を書く

コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile(p); }
- index.htmlを用意する



index.html
<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <h1>Hello World!</h1> </body> </html>
- 公開する





なんか上の方に邪魔なバーが表示される。
ページ遷移の実装
画面遷移の方法がちょっと特殊。 URLに持たせたパラメータを用いて表示するHTMLファイルを切り替える。
コード.gs
function doGet(e) { let p = e.parameter.p; let routes = ['index', 'cat']; if (routes.indexOf(p) != -1) { return HtmlService.createHtmlOutputFromFile(p); } else { return HtmlService.createHtmlOutputFromFile('index'); } }
index.html
<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <h1>Hello World!</h1> <a href="https://script.google.com/macros/s/AKfycby8_E9GjqpntLmf27N7O-SVjNGGaLbLStWQUNCTcUagHQ76ZVs/exec?p=cat">cat.htmlへ移動</a> </body> </html>
cat.html
<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <h1>I love Cat.</h1> <img src="https://1.bp.blogspot.com/-5JQicjad4tU/XQNunlpcxXI/AAAAAAABTJk/GBfBbe-LlGUV5KW5tIFB-xRA3OBl7kjtACLcBGAs/s350/pet_natsukareru_cat_man.png"/> <a href="https://script.google.com/macros/s/AKfycby8_E9GjqpntLmf27N7O-SVjNGGaLbLStWQUNCTcUagHQ76ZVs/exec?p=index">戻る</a> </body> </html>
Project versionをNewにするのを忘れずに!

Bootstrap導入
コード.gsは変わらない。
index.html
<!DOCTYPE html> <html> <head> <base target="_top"> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <title>MyPage</title> </head> <body> <nav class="navbar navbar-dark bg-dark"> <div class="container"> <a class="navbar-brand" href="https://script.google.com/macros/s/AKfycby8_E9GjqpntLmf27N7O-SVjNGGaLbLStWQUNCTcUagHQ76ZVs/exec?p=index">MyPage</a> </div> </nav> <div class="container"> <h1>Hello World!</h1> <a href="https://script.google.com/macros/s/AKfycby8_E9GjqpntLmf27N7O-SVjNGGaLbLStWQUNCTcUagHQ76ZVs/exec?p=cat">cat.htmlへ移動</a> </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script> </body> </html>
cat.html
<!DOCTYPE html> <html> <head> <base target="_top"> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <title>MyPage</title> </head> <body> <nav class="navbar navbar-dark bg-dark"> <div class="container"> <a class="navbar-brand" href="https://script.google.com/macros/s/AKfycby8_E9GjqpntLmf27N7O-SVjNGGaLbLStWQUNCTcUagHQ76ZVs/exec?p=index">MyPage</a> </div> </nav> <div class="container"> <h1>I love Cat.</h1> <img src="https://1.bp.blogspot.com/-5JQicjad4tU/XQNunlpcxXI/AAAAAAABTJk/GBfBbe-LlGUV5KW5tIFB-xRA3OBl7kjtACLcBGAs/s350/pet_natsukareru_cat_man.png"/> <a href="https://script.google.com/macros/s/AKfycby8_E9GjqpntLmf27N7O-SVjNGGaLbLStWQUNCTcUagHQ76ZVs/exec?p=index">戻る</a> </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script> </body> </html>

GASを使ってサイトを作ることで、gmailやスプレッドシートの情報を扱うことができて便利(主に社内向けサイトに使われているみたい)
VueでWebアプリを爆速デプロイしていく
目的
Vueでfirebaseにデプロイする方法を残す
前提
Vue cliの環境は整っている
流れ
- ローカルでVueプロジェクト作成
- firebase console上でプロジェクト作成
- デプロイ準備
- デプロイ
1. ローカルでVueプロジェクト作成
何も考えずEnter
成功
移動し、起動する
この画面が出てきたらよし
これはスキップしていい。
とりあえず、ボタンをクリックしたら新しいタブが100個生成されるWebアプリにした。
2. firebase console上でプロジェクト作成
firebase consoleにアクセスする。
プロジェクトを追加
好きな名前

画面中央の「ウェブ」を選択
好きな名前(URLになる)
3. デプロイ準備
ターミナルで、npm install -g firebase-toolsする(過去にしてればスキップして良い)
firebase login
して、ログインする。
firebase initする。
下矢印キーで移動し、hostingを選択(スペースで選択できる)。
その後、Enterキー。
please select optionでは、Use an existing projectを選択
その後、firebase上で作成したプロジェクト名を選択する
一番注意するポイント
distと入力し、Enter


4. デプロイ
npm run build
firebase deploy
これで表示されるURLをコピーしてブラウザで開くと、動作確認できる。
おまけ
自分の場合はこの画面
ポップアップを許可してあげると。。。

こちらから是非どうぞ( ̄ー ̄人)♪
Ubuntu入れたらすぐにやること集
環境によってやらなくていいものもあり。
Ubuntu18.04
アップデート
sudo apt update && sudo apt upgrade -y
sudo apt-get update && sudo apt-get upgrade -y
フォルダ英語化
LANG=C xdg-user-dirs-gtk-update
ログアウトする
NVIDIAドライバ
sudo ubuntu-drivers devices
モデル名が正しいか確認
sudo ubuntu-drivers autoinstall
無線LAN子機認識させる
sudo apt install git dkms git clone https://github.com/aircrack-ng/rtl8812au.git make -C ./rtl8812au/ cd rtl8812au sudo sh dkms-install.sh
windowsと9時間ずれる問題
timedatectl set-local-rtc 1
Chromeダウンロード
https://www.google.com/intl/ja_jp/chrome/
git
sudo apt install git
github:ssh
mkdir ~/.ssh
cd ~/.ssh
ssh-keygen -t rsa
cat id_rsa.pub
Githubに公開鍵を登録
ssh -T git@github.com
Vim
sudo apt install vim
terminator
sudo apt install terminator
gimp
sudo add-apt-repository ppa:otto-kesselgulasch/gimp
sudo apt install gimp
atom
sudo add-apt-repository ppa:webupd8team/atom
sudo apt install atom
gufw (ファイアウォール)
sudo apt install gufw
openでフォルダを開く
vi ~/.bashrc
以下を追記
alias open='xdg-open'
source ~/.bashrc
MP4
sudo apt-get install ubuntu-restricted-extras
sudo apt-get install ffmpeg
Python (pyenv + pipenv)
sudo apt update && sudo apt install -y --no-install-recommends build-essential libffi-dev libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev git git clone https://github.com/pyenv/pyenv.git ~/.pyenv touch ~/.bash_profile echo -e "# pyenv paths" >> ~/.bash_profile echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile echo 'eval "$(pyenv init -)"' >> ~/.bash_profile source ~/.bash_profile pyenv -v pyenv install 3.8.2 pyenv global 3.8.2 pip install pipenv python -V mkdir 37 cd 37 pipenv install --python 3.7 pipenv shell
Node.js
sudo apt install -y nodejs npm sudo npm install n -g sudo n stable sudo apt purge -y nodejs npm
ターミナルを立ち上げ直す。
参考:
Ubuntu ログインループ問題(NVIDIA)
昨日デスクトップPCにUbuntuを入れたのだが、
問題発生。
ログインできない。
パスワードを忘れたとかではないんよ。
Caps Lockが悪さしてるんかな〜?と最初は思っていたけど、CUIモード(Ctrl + Alt +F2)ならログインできるしどうも違うらしい。
色々調べてみてわかったが、どうやらログインループという現象らしい。
GPUがNVIDIA特有の問題みたいだ。(自分のモデルは、GEFORCE GTX 1050Ti)

玄人志向 ビデオカード GEFORCE GTX 1050Ti搭載 グラフィックボード GF-GTX1050Ti-4GB/OC/SF
- 発売日: 2016/10/25
- メディア: Personal Computers
色々な記事を見て色々な方法でドライバを入れまくったがうまくいかず、しまいにはログイン画面すら開かなくなってしまった。
ということで、インストールからやり直し。
無線LAN子機の認識に関して、記事を残しておいて本当に良かった。
結局、超かんたんにNVIDIAのドライバを入れることができたので、残しとく。
sudo ubuntu-drivers devices
モデル名が正しいか確認
sudo ubuntu-drivers autoinstall
sudo reboot
nvidia-smiでこんな表示になったら成功

またインストールしなおすことになりませんように(@_@)
デスクトップPCにUbuntu環境を構築したら無線LAN対応させるのに苦労したお話
デスクトップPCにUbuntuを入れた
デスクトップPCの特徴

TP-Link WiFi 無線LAN 子機 AC600 433Mbps + 200Mbps Windows/Mac OS 対応 ナノ設計 デュアルバンド 3年保証 Archer T2U Nano
- 発売日: 2019/02/14
- メディア: Personal Computers
SSDはWindows、HHDはUbuntuでデュアルブートする
たまたまUbuntu18.04はUSBに入れて保管していたため、Ubuntu20.04ではなく18.04でいくことに。
HHDをフォーマット。
BIOSからBOOTで、USBを一番上に。
USBに入り、指示されるがままHDDにUbuntuをインストール(ちゃんとSwapもつくったよ)。
無事、成功。
Ubuntuをネットにつなげたい
さあ、初期設定するぞーと思ったら、、、、
ネットにつながらない。
困った。
そこから色々調べて、無事に解決するまでの手順を残しておく(クッソ沼った)。
Ubuntu とWindowsノートPCを有線LANでつないでネットワーク接続をおこなう
無線LAN子機をUbuntuに認識させるためには、一旦ネットにつないで必要なものをインストールしないといけないっぽかった。
そのため、Wi-Fi → ノートPC(Windows) →有線LAN → デスクトップPC(Ubuntu)という構成にする。
- LANケーブルでノートPCとデスクトップPCをつなぐ
Windows側でブリッジする
Windows側でenableにする
- 管理者としてコマンドプロンプトを起動
netsh bridge show adapternetsh bridge set adapter 1 enablenetsh bridge set adapter 2 enablenetsh bridge show adapter
disableからenableになればよし。
Ubuntu に無線LAN子機を認識させる
sudo apt install git dkmsgit clone https://github.com/aircrack-ng/rtl8812au.gitmake -C ./rtl8812au/cd rtl8812ausudo sh dkms-install.sh
無線LAN子機が認識された。 万歳(^^♪
次は、20にアップデートかなあ
Vue.js + Firebase + GitHub認証
JS-proを始めて1週間のVue.js初心者です。
今回は、タイトルにあるように「Vue.js + Firebase + GitHub認証」WEBアプリを実装していきます。
開発環境は、Ubuntu18.04LTS です。
流れは以下の通りです。
さあ、やっていきましょう。
Vue のプロジェクトを作成
npm install -g @vue/clivue create github-auth⚠ここでは、アプリ名をgithub-authにしています。cd github-auth/npm run serveブラウザからlocalhost:8080にアクセスして、この画面が出てくれば成功
Firebaseのプロジェクトを作成
- Firebase コンソールに移動
- プロジェクトを作成

プロジェクトを追加 - ウェブアプリを追加

ウェブアプリを追加
FirebaseとGithubを連携
Authentication

Authentication
赤線のURLをコピーしておく
アプリを登録する
Application name : my-github-auth(アプリ名)
Homepage URL : ペーストし、末尾が.firebaseapp.com/になるようにする
Authorization callback URL : ペーストする

クライアントIDとクライアントシークレットをFirebase側に貼り付け
赤部分

GitHubが有効になれば成功

Vue のソースコードをいい感じに
Firebaseプロジェクトの設定を開く

設定を開く Firebase側の情報をコピー

赤の部分 src/main.jsに貼り付け
import firebase from 'firebase' import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false // Your web app's Firebase configuration var firebaseConfig = { apiKey: "見せられないよ", authDomain: "github-auth-6d6da.firebaseapp.com", databaseURL: "https://github-auth-6d6da.firebaseio.com", projectId: "github-auth-6d6da", storageBucket: "github-auth-6d6da.appspot.com", messagingSenderId: "見せられないよ", appId: "見せられないよ" }; // Initialize Firebase firebase.initializeApp(firebaseConfig); new Vue({ render: h => h(App), }).$mount('#app')
src/App.vue
<template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png"> <GithubAuth msg="Welcome to Github-Auth"/> </div> </template> <script> import GithubAuth from './components/GithubAuth.vue' export default { name: 'App', components: { GithubAuth } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
src/components/GithubAuth.vue
<template> <div class="github-auth"> <h1>{{ msg }}</h1> <div v-if="user.uid" key="login"> <img :src="user.photoURL"/><br> [{{ user.displayName }}]<br> <button type="button" @click="doLogout">ログアウト</button> </div> <!-- 未ログイン時にはログインボタンを表示 --> <div v-else key="logout"> <button type="button" @click="doLogin">ログイン</button> </div> </div> </template> <script> import firebase from 'firebase' export default { name: 'GithubAuth', props: { msg: String }, data() { return { user: {} } }, created() { firebase.auth().onAuthStateChanged(user => { this.user = user ? user : {} }) }, methods: { doLogin() { console.log("doLogin"); const provider = new firebase.auth.GithubAuthProvider(); firebase.auth().signInWithPopup(provider) }, doLogout() { console.log("doLogout"); firebase.auth().signOut() } } } </script>
完成
npm install firebasenpm run serve- ブラウザで
localhost:8080にアクセス


参考文献
Vue.js+Firebaseで認証付きチャット | 基礎から学ぶ Vue.js
JavaScript による GitHub を使用した認証 | Firebase
ソースコード
【LINEbot】天気予報くんをつくる(その3 データベース)
つづき
実現したい機能
地域登録
ユーザーIDと地域を結びつけることで、天気を知りやすくする。
ソースコード
main.py
from flask import Flask, request, abort from flask_sqlalchemy import SQLAlchemy from linebot import ( LineBotApi, WebhookHandler ) from linebot.exceptions import ( InvalidSignatureError ) from linebot.models import ( MessageEvent, TextMessage, TextSendMessage, TemplateSendMessage, ConfirmTemplate, PostbackAction, PostbackEvent ) import os import requests as rq import json import pickle app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL'] db = SQLAlchemy(app) LINE_CHANNEL_ACCESS_TOKEN = os.environ["LINE_CHANNEL_ACCESS_TOKEN"] LINE_CHANNEL_SECRET = os.environ["LINE_CHANNEL_SECRET"] line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN) handler = WebhookHandler(LINE_CHANNEL_SECRET) city_path = 'city_dict.pickle' with open(city_path, mode='rb') as f: city_dict = pickle.load(f) city_list = list(city_dict.keys()) def get_weather_info(city_num): url = 'http://weather.livedoor.com/forecast/webservice/json/v1?' city_params = {'city': city_num} data = rq.get(url, params=city_params) content = json.loads(data.text) content_title = format(content['title']) content_text = format(content['description']['text']) content_time = format(content['description']['publicTime'])\ .replace('T', ' ').replace('-', '/')[:-5] return content_title + '\n\n' + content_text + '\n\n最終更新日時:' + content_time # モデル作成 class MyCity(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.String(80)) city_id = db.Column(db.String(80)) def __init__(self, user_id, city_id): self.user_id = user_id self.city_id = city_id def register_mycity(user_id, city_id): my_city = db.session.query(MyCity).filter(MyCity.user_id==user_id).first() if my_city: old_my_city_id = my_city.city_id my_city.city_id = city_id db.session.commit() else: reg = MyCity(user_id, city_id) db.session.add(reg) db.session.commit() @app.route("/callback", methods=['POST']) def callback(): signature = request.headers['X-Line-Signature'] body = request.get_data(as_text=True) app.logger.info("Request body: " + body) try: handler.handle(body, signature) except InvalidSignatureError: abort(400) return 'OK' @handler.add(PostbackEvent) def handle_postback(event): postback_data = event.postback.data if postback_data == 'no': text_message = 'かしこまりました' else: user_id = event.source.user_id register_mycity(user_id, postback_data) text_message = '登録しました' line_bot_api.reply_message( event.reply_token, TextSendMessage(text=text_message)) @handler.add(MessageEvent, message=TextMessage) def handle_message(event): user_message = event.message.text if user_message in city_list: city_id = city_dict[user_message] text_message = get_weather_info(city_id) confirm_template_message = TemplateSendMessage( alt_text='Confirm template', template=ConfirmTemplate( text=user_message + 'を登録しますか?', actions=[ PostbackAction( label='はい', display_text='はい', data=city_id ), PostbackAction( label='いいえ', display_text='いいえ', data='no' ) ] ) ) messages = [TextSendMessage(text=text_message), confirm_template_message] elif '一覧' in user_message: text_message = '以下、対応地域一覧です。\n' + '\n'.join(city_list) messages = [TextSendMessage(text=text_message)] else: my_city = db.session.query(MyCity).filter(MyCity.user_id==event.source.user_id).first() if my_city: text_message1 = get_weather_info(my_city.city_id) text_message2 = '対応地域を知りたい場合は、「一覧」と話しかけてください。' messages = [TextSendMessage(text=text_message1), TextSendMessage(text=text_message2)] else: text_message1 = '久留米' text_message2 = '上記、入力例です。以下、対応地域一覧です。\n' + '\n'.join(city_list) messages = [TextSendMessage(text=text_message1), TextSendMessage(text=text_message2)] line_bot_api.reply_message( event.reply_token, messages) if __name__ == "__main__": port = int(os.getenv("PORT", 5000)) app.run(host="0.0.0.0", port=port)
その他省略 以下、リポジトリにて
手順
pipenv install flask-sqlalchemy psycopg2
エラーになった。
sudo apt install libpq-dev
上のコマンド実行後、再挑戦したら通った。Heroku側にPostgresのアドオンを追加
heroku addons:add heroku-postgresqlテーブル作成
$heroku run python >>> from main import db >>> db.create_all()
これで動く
以下、時々使う
データベースのリセット
heroku pg:reset DATABASE --confirm <app-name>
Herokuからデータベースを確認
$heroku run python >>> from main import db, <Class Name> >>> db.session.query(<Class Name>).all()
動作





感想
せっかく、LINEbotの扱いを覚えたので今後すぐに思い出せるようにこの記事を書いた。 一ヶ月近く前にLINEbotを扱ったのだが、少し忘れているところもあり、いい復習になった。 地域名の選択を、プルダウンみたくやりたかったのだができないのだろうか。 効率よくできる案があればぜひ教えていただきたい。
LINEID
@872alddw

参考記事
PostgreSQLを用いたFlaskアプリのHerokuデプロイ(Flask-SQLAlchemy) - Qiita
line-bot-sdk-python/app.py at master · line/line-bot-sdk-python · GitHub
