diff --git a/.circleci/config.yml b/.circleci/config.yml index 2408d05..f417ac5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,7 +57,7 @@ jobs: root: . paths: - . - golint: + lint: machine: true steps: - attach_workspace: @@ -66,8 +66,8 @@ jobs: - *load_docker_image - *run_docker_compose - run: - name: Run golint - command: make lint + name: Run lint + command: npm run lint test: machine: true steps: @@ -78,13 +78,13 @@ jobs: - *run_docker_compose - run: name: Run tests - command: make test + command: npm run test:unit workflows: version: 2 build_and_test: jobs: - build - - golint: + - lint: requires: - build - test: diff --git a/Makefile b/Makefile index c372a8a..4307ffb 100644 --- a/Makefile +++ b/Makefile @@ -31,13 +31,4 @@ ifeq ($(env), ci) docker-compose -f docker-compose.ci.yml pull else docker-compose -f docker-compose.yml pull -endif - -lint: ## Run golint. - docker exec -it gobel-admin-client golint ./... - -test: ## Run tests. - docker exec -it gobel-admin-client go test -v ./... - -build: ## Run go build - cd app && GOOS=linux GOARCH=amd64 go build -o app \ No newline at end of file +endif \ No newline at end of file diff --git a/README.md b/README.md index bbb4b20..958cf1d 100644 --- a/README.md +++ b/README.md @@ -13,16 +13,37 @@ This is an example for admin client application of gobel. # Requirements -- Docker Compose - -# Requirements - +- Docker - Docker Compose # Get started Before you start, you need to clone [gobel-api](https://github.com/bmf-san/gobel-api). +``` +npm install +``` + +# Scripts +## Compiles and hot-reloads for development +``` +npm run serve +``` + +## Compiles and minifies for production +``` +npm run build +``` + +## Run your unit tests +``` +npm run test:unit +``` + +## Lints and fixes files +``` +npm run lint +``` # Contributing We welcome your issue or pull request from everyone. diff --git a/app/Dockerfile b/app/Dockerfile index 251ffcc..d607989 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -6,12 +6,12 @@ COPY package*.json ./ RUN npm install -COPY ./ . +COPY . . RUN npm run local-build FROM nginx:1.19.0-alpine COPY ./nginx/nginx.conf /etc/nginx/nginx.conf -COPY ./nginx/conf.d/gobel-admin-client.conf /etc/nginx/conf.d/goble-admin-client-example.conf +COPY ./nginx/conf.d/gobel-admin-client.conf /etc/nginx/conf.d/gobel-admin-client.conf COPY --from=build-stage /app/dist /var/www/html \ No newline at end of file diff --git a/app/Dockerfile.prod b/app/Dockerfile.prod index 06b86b6..01661e4 100644 --- a/app/Dockerfile.prod +++ b/app/Dockerfile.prod @@ -12,4 +12,4 @@ RUN npm run prod-build FROM alpine -COPY --from=build-stage /app/dist /var/www/html \ No newline at end of file +COPY --from=build-stage /app/dist/ ./ \ No newline at end of file diff --git a/app/README.md b/app/README.md deleted file mode 100644 index 4fc27fa..0000000 --- a/app/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# app - -## Project setup -``` -npm install -``` - -### Compiles and hot-reloads for development -``` -npm run serve -``` - -### Compiles and minifies for production -``` -npm run build -``` - -### Run your unit tests -``` -npm run test:unit -``` - -### Lints and fixes files -``` -npm run lint -``` - -### Customize configuration -See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/app/nginx/conf.d/gobel-admin-client-example.conf b/app/nginx/conf.d/gobel-admin-client.conf similarity index 60% rename from app/nginx/conf.d/gobel-admin-client-example.conf rename to app/nginx/conf.d/gobel-admin-client.conf index a2820e9..79ac4c4 100644 --- a/app/nginx/conf.d/gobel-admin-client-example.conf +++ b/app/nginx/conf.d/gobel-admin-client.conf @@ -2,8 +2,8 @@ server { listen 80; server_name gobel-admin-client.local; charset UTF-8; - access_log /var/log/nginx/access_gobel_admin_client_example.log; - error_log /var/log/nginx/error_gobel_admin_client_example.log; + access_log /var/log/nginx/access_gobel_admin_client.log; + error_log /var/log/nginx/error_gobel_admin_client.log; location / { root /var/www/html; diff --git a/app/package.json b/app/package.json index cd04be4..a827d60 100644 --- a/app/package.json +++ b/app/package.json @@ -6,7 +6,7 @@ "serve": "vue-cli-service serve", "local-build": "vue-cli-service build --mode=local", "prod-build": "vue-cli-service build --mode-production", - "test:unit": "vue-cli-service test:unit", + "test:unit": "vue-cli-service test:unit --u", "lint": "vue-cli-service lint" }, "dependencies": { diff --git a/app/src/App.vue b/app/src/App.vue index 9f40069..7129d0e 100644 --- a/app/src/App.vue +++ b/app/src/App.vue @@ -1,9 +1,58 @@ + + diff --git a/app/src/components/Pagination.vue b/app/src/components/Pagination.vue new file mode 100644 index 0000000..6a9c90d --- /dev/null +++ b/app/src/components/Pagination.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/app/src/components/Signout.vue b/app/src/components/Signout.vue deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/consts/posts.js b/app/src/consts/posts.js new file mode 100644 index 0000000..7ceb23b --- /dev/null +++ b/app/src/consts/posts.js @@ -0,0 +1,8 @@ +const PUBLISH = "publish"; +const DRAFT = "draft"; + +export default Object.freeze({ + STATUS_PUBLIC: PUBLISH, + STATUS_PRIVATE: DRAFT, + STATUSES: [PUBLISH, DRAFT] +}); diff --git a/app/src/modules/apiClient.js b/app/src/modules/apiClient.js index c95ecb0..3534c43 100644 --- a/app/src/modules/apiClient.js +++ b/app/src/modules/apiClient.js @@ -5,12 +5,11 @@ import router from "../router"; const apiClient = axios.create({ baseURL: process.env.VUE_APP_API_ENDPOINT, headers: { - "Content-Type": "application/json", + "Content-Type": "application/json" }, responseType: "json" }); -// TODO: 動作確認ちゃんとしていないので後でする apiClient.interceptors.response.use( res => { // if the api request is successful, return response as it is. @@ -21,11 +20,11 @@ apiClient.interceptors.response.use( if (error.config && error.response && error.response.status === 401) { apiClient .post( - "/refresh", + "/private/refresh", {}, { headers: { - 'Authorization': "Bearer " + localStorage.getItem("refresh_token"), + Authorization: "Bearer " + localStorage.getItem("refresh_token") } } ) @@ -34,7 +33,7 @@ apiClient.interceptors.response.use( const config = error.config; localStorage.setItem("access_token", res.data.access_token); localStorage.setItem("refresh_token", res.data.refresh_token); - config.headers["Authorization"] = res.data.refresh_token; + config.headers["Authorization"] = "Bearer " + res.data.access_token; // Retry the api request. return Axios.request(error.config); diff --git a/app/src/pages/CreatePost.vue b/app/src/pages/CreatePost.vue new file mode 100644 index 0000000..cce054e --- /dev/null +++ b/app/src/pages/CreatePost.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/app/src/pages/EditPost.vue b/app/src/pages/EditPost.vue index 72906f7..a7f6052 100644 --- a/app/src/pages/EditPost.vue +++ b/app/src/pages/EditPost.vue @@ -3,16 +3,35 @@

EditPost

-
- + + + - + :taggable="true" + > + + +
@@ -21,60 +40,71 @@ - + diff --git a/app/src/pages/Posts.vue b/app/src/pages/Posts.vue index f462e93..334535a 100644 --- a/app/src/pages/Posts.vue +++ b/app/src/pages/Posts.vue @@ -3,45 +3,71 @@

Posts

- - posts list +
+

{{ post.title }}

+
+
- + diff --git a/app/src/pages/Signin.vue b/app/src/pages/Signin.vue index 6db2249..dffeb17 100644 --- a/app/src/pages/Signin.vue +++ b/app/src/pages/Signin.vue @@ -2,7 +2,6 @@

Login

-
diff --git a/app/src/router/index.js b/app/src/router/index.js index 569b6b6..ffe2676 100644 --- a/app/src/router/index.js +++ b/app/src/router/index.js @@ -4,6 +4,7 @@ import Signin from "../pages/Signin.vue"; import Home from "../pages/Home.vue"; import Posts from "../pages/Posts.vue"; import EditPost from "../pages/EditPost.vue"; +import CreatePost from "../pages/CreatePost.vue"; import apiClient from "../modules/apiClient"; Vue.use(VueRouter); @@ -26,18 +27,18 @@ const routes = [ component: Posts, meta: { requiresAuth: true } }, + { + path: "/posts/create", + name: "CreatePost", + component: CreatePost, + meta: { requiresAuth: true } + }, { path: "/posts/:id", name: "EditPost", component: EditPost, meta: { requiresAuth: true } } - // { - // path: "/posts/create", - // name: "NewPost", - // component: NewPost, - // meta: { requiresAuth: true } - // }, ]; const router = new VueRouter({ @@ -48,24 +49,22 @@ const router = new VueRouter({ router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { + // if the request fails, apiclient intercepts responses. apiClient .get("/private/me", { headers: { - 'Authorization': "Bearer " + localStorage.getItem("access_token"), + Authorization: "Bearer " + localStorage.getItem("access_token") } }) .then(function() { - // TODO: Get admin data from response and set it to state or something for output admin data to views. Maybe this case needs store pattern. next(); }) .catch(function(error) { console.log(error); - next({ - path: "/signin", - }); + next(); }); } else { - next() + next(); } }); diff --git a/app/tests/unit/components/__snapshots__/pagination.spec.js.snap b/app/tests/unit/components/__snapshots__/pagination.spec.js.snap new file mode 100644 index 0000000..cf9af5f --- /dev/null +++ b/app/tests/unit/components/__snapshots__/pagination.spec.js.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Pagination.vue matched snapshot 1`] = `
    `; diff --git a/app/tests/unit/components/pagination.spec.js b/app/tests/unit/components/pagination.spec.js new file mode 100644 index 0000000..dc478e9 --- /dev/null +++ b/app/tests/unit/components/pagination.spec.js @@ -0,0 +1,14 @@ +import { shallowMount } from "@vue/test-utils"; +import Pagination from "@/components/Pagination.vue"; + +describe("Pagination.vue", () => { + it("init", () => { + const wrapper = shallowMount(Pagination); + expect(wrapper.isVueInstance).toBeTruthy(); + }); + + it("matched snapshot", () => { + const wrapper = shallowMount(Pagination); + expect(wrapper.html()).toMatchSnapshot(); + }); +});