diff --git a/.github/workflows/cd-chienlv.yml b/.github/workflows/cd-chienlv.yml new file mode 100644 index 000000000..d53833445 --- /dev/null +++ b/.github/workflows/cd-chienlv.yml @@ -0,0 +1,36 @@ +name: Build Dockerfile and push + +on: + push: + tags: + - v* + +jobs: + docker: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push app image + uses: docker/build-push-action@v4 + with: + context: 1. Containerization/Le Van Chien/app/ + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/app:${{ github.ref_name }} + + - name: Build and push web image + uses: docker/build-push-action@v4 + with: + context: 1. Containerization/Le Van Chien/nginx/ + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/web:${{ github.ref_name }} diff --git a/.github/workflows/ci-chienlv.yml b/.github/workflows/ci-chienlv.yml new file mode 100644 index 000000000..2fd58f0c6 --- /dev/null +++ b/.github/workflows/ci-chienlv.yml @@ -0,0 +1,30 @@ +name: CI + +on: + push: + branches: + - midterm + pull_request: + branches: + - midterm + +jobs: + test: + runs-on: ubuntu-20.04 + + steps: + - name: checkout code + uses: actions/checkout@v3 + + - name: setup Python + uses: actions/setup-python@v3 + with: + python-version: 3.8 + + - name: install dependencies + run: | + pip install --upgrade pip + pip install -r 1.\ Containerization/Le\ Van\ Chien/app/tests/test_requirements.txt + - name: run tests + working-directory: 1. Containerization/Le Van Chien/app + run: pytest diff --git a/1. Containerization/Le Van Chien/.gitignore b/1. Containerization/Le Van Chien/.gitignore index f7655e0fd..8da8a8d99 100644 --- a/1. Containerization/Le Van Chien/.gitignore +++ b/1. Containerization/Le Van Chien/.gitignore @@ -2,5 +2,4 @@ /env db/* !db/.gitkeep -ansible/collections/ansible_collections/* -!ansible/collections/ansible_collections/.gitkeep +/app/*/__pycache__ \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/ansible/roles/api/defaults/main.yaml b/1. Containerization/Le Van Chien/ansible/roles/api/defaults/main.yaml deleted file mode 100644 index f1cc91684..000000000 --- a/1. Containerization/Le Van Chien/ansible/roles/api/defaults/main.yaml +++ /dev/null @@ -1,16 +0,0 @@ -user: lechiennn -source_folder: ../app -dest_folder: "/home/{{ user }}/test/" - -image_name: api -image_state: present -resources_path: "{{ dest_folder }}/app" - -container_name: ap -ports: - - "5000:5000" -container_state: started -volumes: - - "{{ resources_path }}:/app" - -network_name: net \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/ansible/roles/common/tasks/setup_ubuntu.yaml b/1. Containerization/Le Van Chien/ansible/roles/common/tasks/setup_ubuntu.yaml deleted file mode 100644 index 8a8917add..000000000 --- a/1. Containerization/Le Van Chien/ansible/roles/common/tasks/setup_ubuntu.yaml +++ /dev/null @@ -1,85 +0,0 @@ ---- -- name: Ensure old versions of Docker are not installed. - package: - name: - - docker - - docker-engine - state: absent - -- name: Ensure dependencies are installed. - apt: - name: - - apt-transport-https - - ca-certificates - state: present - - -# - name: Ensure additional dependencies are installed (on Ubuntu < 20.04 and any other systems). -# apt: -# name: gnupg2 -# state: present -# when: ansible_distribution != 'Ubuntu' or ansible_distribution_version is version('20.04', '<') - -- name: Ensure additional dependencies are installed (on Ubuntu >= 20.04). - apt: - name: gnupg - state: present - -- name: Add Docker apt key. - ansible.builtin.get_url: - url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg" - dest: /etc/apt/trusted.gpg.d/docker.asc - mode: '0644' - force: true - ignore_errors: true - - -# - name: Ensure curl is present (on older systems without SNI). -# package: name=curl state=present -# when: add_repository_key is failed and docker_add_repo | bool - -# - name: Add Docker apt key (alternative for older systems without SNI). -# shell: > -# curl -sSL {{ docker_apt_gpg_key }} | apt-key add - -# when: add_repository_key is failed and docker_add_repo | bool - -- name: Add Docker repository. - apt_repository: - repo: "{{ docker_apt_repository }}" - state: present - update_cache: true - -# - name: Install required package -# package: -# name: -# - ca-certificates -# - curl -# - gnupg -# state: present -# update_cache: true - -# - name: Add Docker apt key. -# get_url: -# url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg -# dest: /etc/apt/trusted.gpg.d/docker.asc -# mode: '0644' -# force: true -# register: add_repository_key -# ignore_errors: false - -# - name: Add Docker repository. -# apt_repository: -# repo: "deb [arch={{ ansible_architecture }}] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable" -# state: present -# update_cache: true - -#### -# - name: Add GPG key -# apt_key: -# url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg -# state: present - -# - name: Add repository -# apt_repository: -# repo: "deb [arch={{ ansible_architecture }}] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable" -# state: present \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/ansible/roles/web/defaults/main.yaml b/1. Containerization/Le Van Chien/ansible/roles/web/defaults/main.yaml deleted file mode 100644 index a3b76f247..000000000 --- a/1. Containerization/Le Van Chien/ansible/roles/web/defaults/main.yaml +++ /dev/null @@ -1,12 +0,0 @@ -user: lechiennn -source_folder: ../nginx -dest_folder: "/home/{{ user }}/test/" - -image_name: nginx:1.22.0-alpine -container_name: web -ports: - - "8080:80" -container_state: started -volumes: - - "{{ dest_folder }}/nginx/nginx.conf:/etc/nginx/nginx.conf" - - "{{ dest_folder }}/nginx/static:/var/www/html" \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/ansible/roles/web/tasks/main.yaml b/1. Containerization/Le Van Chien/ansible/roles/web/tasks/main.yaml deleted file mode 100644 index 644acc9a8..000000000 --- a/1. Containerization/Le Van Chien/ansible/roles/web/tasks/main.yaml +++ /dev/null @@ -1,13 +0,0 @@ -- name: copy resources from host - copy: - src: "{{ source_folder }}" - dest: "{{ dest_folder }}" - force: false - -- name: run Docker container - community.docker.docker_container: - name: "{{ container_name }}" - image: "{{ image_name }}" - state: "{{ container_state }}" - ports: "{{ ports }}" - volumes: "{{ volumes }}" \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/app/.dockerignore b/1. Containerization/Le Van Chien/app/.dockerignore new file mode 100644 index 000000000..2b6425147 --- /dev/null +++ b/1. Containerization/Le Van Chien/app/.dockerignore @@ -0,0 +1,2 @@ +/tests +/.pytest_cache \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/app/app.py b/1. Containerization/Le Van Chien/app/app.py index 5925fab06..a9cc5c8b5 100644 --- a/1. Containerization/Le Van Chien/app/app.py +++ b/1. Containerization/Le Van Chien/app/app.py @@ -1,29 +1,59 @@ -from flask import Flask -from pymongo import MongoClient -from flask_cors import CORS, cross_origin -import json -from bson import json_util +from project.api import create_app +from project.database import create_db -app = Flask(__name__) -cors = CORS(app) +db = create_db() +app = create_app(db) +if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0', port=5000) -client = MongoClient('mongodb://db:27017') -client.drop_database('attendee') -db = client.attendee -if 'attendees' not in db.list_collection_names(): - with open('data/attendees.json') as f: - data = json.load(f) - db.attendees.insert_many(data) +# from flask import Flask, request +# from pymongo import MongoClient +# from flask_cors import CORS, cross_origin +# import json +# from bson import json_util -@app.route('/people/', methods = ['GET']) -def getAll(): - attendees = json_util.dumps(db.attendees.find({})) - return attendees +# app = Flask(__name__) +# cors = CORS(app, resources={r'/people/*': {'origins': '*'}}) -@app.route('/people/', methods = ['GET']) -def get(num): - return json_util.dumps(db.attendees.find({"no": num})) +# client = MongoClient('mongodb://db:27017') +# client.drop_database('attendee') +# db = client.attendee +# if 'attendees' not in db.list_collection_names(): +# with open('data/attendees.json') as f: +# data = json.load(f) +# db.attendees.insert_many(data) +# @app.route('/people/', methods = ['GET']) +# def getAll(): +# attendees = json_util.dumps(db.attendees.find({})) +# return attendees -if __name__ == '__main__': - app.run(debug=True, host='0.0.0.0', port=5000) +# @app.route('/people/', methods = ['GET']) +# def getByID(num): +# return json_util.dumps(db.attendees.find({"id": num})) + +# @app.route('/people/', methods = ['GET']) +# def getByUsername(username): +# return json_util.dumps(db.attendees.find({"username": username})) + +# @app.route('/people/delete/', methods = ['DELETE']) +# def delete(username): +# db.attendees.delete_one({'username': username}) +# return json_util.dumps({'message': f'Resource with username {username} deleted'}) + + +# @app.route('/people/create/', methods = ['PUT']) +# def create(): +# data = request.get_json() +# db.attendees.insert_one(data) +# return json_util.dumps({'message': 'Resource with username {} created'.format(data['username'])}) + +# @app.route('/people/update/', methods = ['PUT']) +# def update(username): +# data = request.get_json() +# db.attendees.update_one({'username':username}, data) +# return json_util.dumps({'message': 'Resource with username {} updated'.format(username)}) + + +# if __name__ == '__main__': +# app.run(debug=True, host='0.0.0.0', port=5000) \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/app/data/attendees.json b/1. Containerization/Le Van Chien/app/data/attendees.json index 18e74e346..199ba9f10 100644 --- a/1. Containerization/Le Van Chien/app/data/attendees.json +++ b/1. Containerization/Le Van Chien/app/data/attendees.json @@ -1,282 +1,317 @@ [ { - "no": 1, - "name": "Bùi Minh Sơn", - "yob": 2002, - "sex": "Nam", - "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", - "major": "Công nghệ thông tin" - }, - { - "no": 2, - "name": "Đào Đại Hiệp", - "yob": 2001, - "sex": "Nam", - "school": "Đại học Bách khoa Hà Nội", - "major": "Điện tử viễn thông" - }, - { - "no": 3, - "name": "Đỗ Anh Tú", - "yob": 2002, - "sex": "Nam", - "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", - "major": "Mạng máy tính và truyền thông dữ liệu" - }, - { - "no": 4, - "name": "Đỗ Bảo Hoàng", - "yob": 1997, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "An toàn thông tin" - }, - { - "no": 5, - "name": "Hoàng Quốc Doanh", - "yob": 2001, - "sex": "Nam", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "NULL" - }, - { - "no": 6, - "name": "Le Minh Duc", - "yob": 2002, - "sex": "Nam", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "Công nghệ thông tin ứng dụng phần mềm" - }, - { - "no": 7, - "name": "Lê Phúc Lai", - "yob": 2002, - "sex": "Nam", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "Kỹ thuật điện tử viễn thông" - }, - { - "no": 8, - "name": "Lê Quang Anh", - "yob": 1997, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "An toàn thông tin" - }, - { - "no": 9, - "name": "Lê Trọng Minh", - "yob": 2000, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "Kỹ thuật điều khiển và tự động hóa" - }, - { - "no": 10, - "name": "Lê Tùng Lâm", - "yob": 1999, - "sex": "Nam", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "Khoa học máy tính" - }, - { - "no": 11, - "name": "Lê Văn Chiến", - "yob": 2002, - "sex": "Nam", - "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", - "major": "Kỹ thuật hàng không vũ trụ" - }, - { - "no": 12, - "name": "Linh Thi Nguyen", - "yob": 2002, - "sex": "Nữ", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "ICT" - }, - { - "no": 13, - "name": "Nguyễn Đại An", - "yob": 2023, - "sex": "Nam", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "Khoa học máy tính" - }, - { - "no": 14, - "name": "Nguyễn Đình Hoàng", - "yob": 2002, - "sex": "Nam", - "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", - "major": "Công nghệ thông tin ứng dụng phần mềm" - }, - { - "no": 15, - "name": "Nguyen Duc Vinh Data", - "yob": 2002, - "sex": "Nam", - "school": "Học viện Công nghệ Bưu chính Viễn thông", - "major": "NULL" - }, - { - "no": 16, - "name": "Nguyễn Dương Long", - "yob": 2002, - "sex": "Nam", - "school": "ĐH Thuỷ lợi", - "major": "Công nghệ thông tin ứng dụng phần mềm" - }, - { - "no": 17, - "name": "Nguyen Huu Thang", - "yob": 2000, - "sex": "Nam", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "Khoa học máy tính" - }, - { - "no": 18, - "name": "Nguyễn Mạnh Cường", - "yob": 1997, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "Điện tử" - }, - { - "no": 19, - "name": "Nguyễn Mạnh Đức", - "yob": 2002, - "sex": "Nam", - "school": "Học viện Kỹ thuật mật mã", - "major": "An toàn thông tin" - }, - { - "no": 20, - "name": "Nguyễn Ngọc Chung", - "yob": 2002, - "sex": "Nam", - "school": "Học viên Công nghệ Bưu chính Viễn Thông HCM", - "major": "NULL" - }, - { - "no": 21, - "name": "Nguyễn Tuấn Anh", - "yob": 1997, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "An toàn thông tin" - }, - { - "no": 22, - "name": "Nguyễn Văn Quang", - "yob": 1997, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "An toàn thông tin" - }, - { - "no": 23, - "name": "Ninh Chí Hướng", - "yob": 2002, - "sex": "Nam", - "school": "Học viện Công nghệ Bưu chính viễn thông", - "major": "An toàn thông tin" - }, - { - "no": 24, - "name": "Ninh Văn Nghĩa", - "yob": 2001, - "sex": "Nam", - "school": "Đại Học Bách Khoa Hà Nội", - "major": "Khoa học máy tính" - }, - { - "no": 25, - "name": "Phạm Anh Đức", - "yob": 2001, - "sex": "Nam", - "school": "Đại học Bách Khoa Hà Nội", - "major": "Toán ứng dụng và tin học" - }, - { - "no": 26, - "name": "Phạm Duy Cương", - "yob": 1997, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "Công nghệ điện tử" - }, - { - "no": 27, - "name": "Phạm Hồng Thanh", - "yob": 1998, - "sex": "Nam", - "school": "Swinburne University", - "major": "Phát triển phần mềm" - }, - { - "no": 28, - "name": "Phạm Thị Khánh Linh", - "yob": 2002, - "sex": "Nữ", - "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", - "major": "Mạng máy tính và truyền thông dữ liệu" - }, - { - "no": 29, - "name": "Phạm Văn Tới", - "yob": 2002, - "sex": "Nam", - "school": "Học viện Công nghệ Bưu chính viễn thông", - "major": "Công nghệ thông tin ứng dụng phần mềm" - }, - { - "no": 30, - "name": "Trần Đức Mạnh", - "yob": 1998, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "Bảo mật thông tin" - }, - { - "no": 31, - "name": "Trần Mạnh Dũng", - "yob": 2001, - "sex": "Nam", - "school": "Học viện Công nghệ Bưu chính Viễn thông", - "major": "Điện tử viễn thông" - }, - { - "no": 32, - "name": "Trần Minh Dương", - "yob": 2002, - "sex": "Nam", - "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", - "major": "Mạng máy tính và truyền thông dữ liệu" - }, - { - "no": 33, - "name": "Trần Xuân Phú", - "yob": 2001, - "sex": "Nam", - "school": "Trường Đại học Công nghệ thông tin - ĐHQG Tp.Hồ chí Minh", - "major": "Khoa học máy tính" - }, - { - "no": 34, - "name": "Vũ Hoàng Long", - "yob": 2001, - "sex": "Nam", - "school": "Đại học Bách Khoa Hà Nội", - "major": "Khoa học máy tính" - }, - { - "no": 35, - "name": "Vũ Minh Hiếu", - "yob": 2000, - "sex": "Nam", - "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", - "major": "Kỹ thuật phần mềm" + "id": 1, + "name": "Bùi Minh Sơn", + "username": "sonbm", + "yob": 2002, + "sex": "Nam", + "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", + "major": "Công nghệ thông tin" + }, + { + "id": 2, + "name": "Đào Đại Hiệp", + "username": "hiepdd", + "yob": 2001, + "sex": "Nam", + "school": "Đại học Bách khoa Hà Nội", + "major": "Điện tử viễn thông" + }, + { + "id": 3, + "name": "Đỗ Anh Tú", + "username": "tuda", + "yob": 2002, + "sex": "Nam", + "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", + "major": "Mạng máy tính và truyền thông dữ liệu" + }, + { + "id": 4, + "name": "Đỗ Bảo Hoàng", + "username": "hoangdb", + "yob": 1997, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "An toàn thông tin" + }, + { + "id": 5, + "name": "Hoàng Quốc Doanh", + "username": "doanhhq", + "yob": 2001, + "sex": "Nam", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "NULL" + }, + { + "id": 6, + "name": "Lê Minh Đức", + "username": "duclm", + "yob": 2002, + "sex": "Nam", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "Công nghệ thông tin ứng dụng phần mềm" + }, + { + "id": 7, + "name": "Lê Phúc Lai", + "username": "lailp", + "yob": 2002, + "sex": "Nam", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "Kỹ thuật điện tử viễn thông" + }, + { + "id": 8, + "name": "Lê Quang Anh", + "username": "anhlq", + "yob": 1997, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "An toàn thông tin" + }, + { + "id": 9, + "name": "Lê Trọng Minh", + "username": "minhlt", + "yob": 2000, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "Kỹ thuật điều khiển và tự động hóa" + }, + { + "id": 10, + "name": "Lê Tùng Lâm", + "username": "lamlt", + "yob": 1999, + "sex": "Nam", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "Khoa học máy tính" + }, + { + "id": 11, + "name": "Lê Văn Chiến", + "username": "chienlv", + "yob": 2002, + "sex": "Nam", + "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", + "major": "Kỹ thuật hàng không vũ trụ" + }, + { + "id": 12, + "name": "Nguyễn Thị Linh", + "username": "linhnt", + "yob": 2002, + "sex": "Nữ", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "ICT" + }, + { + "id": 13, + "name": "Nguyễn Đại An", + "username": "annd", + "yob": 2023, + "sex": "Nam", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "Khoa học máy tính" + }, + { + "id": 14, + "name": "Nguyễn Đình Hoàng", + "username": "hoangnd", + "yob": 2002, + "sex": "Nam", + "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", + "major": "Công nghệ thông tin ứng dụng phần mềm" + }, + { + "id": 15, + "name": "Nguyễn Đức Vinh", + "username": "vinhnd", + "yob": 2002, + "sex": "Nam", + "school": "Học viện Công nghệ Bưu chính Viễn thông", + "major": "NULL" + }, + { + "id": 16, + "name": "Nguyễn Dương Long", + "username": "longnd", + "yob": 2002, + "sex": "Nam", + "school": "ĐH Thuỷ lợi", + "major": "Công nghệ thông tin ứng dụng phần mềm" + }, + { + "id": 17, + "name": "Nguyễn Hữu Thắng", + "username": "thangnh", + "yob": 2000, + "sex": "Nam", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "Khoa học máy tính" + }, + { + "id": 18, + "name": "Nguyễn Mạnh Cường", + "username": "cuongnm", + "yob": 1997, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "Điện tử" + }, + { + "id": 19, + "name": "Nguyễn Mạnh Đức", + "username": "ducnm", + "yob": 2002, + "sex": "Nam", + "school": "Học viện Kỹ thuật mật mã", + "major": "An toàn thông tin" + }, + { + "id": 20, + "name": "Nguyễn Ngọc Chung", + "username": "chungnn", + "yob": 2002, + "sex": "Nam", + "school": "Học viên Công nghệ Bưu chính Viễn Thông HCM", + "major": "NULL" + }, + { + "id": 21, + "name": "Nguyễn Tuấn Anh", + "username": "anhnt", + "yob": 1997, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "An toàn thông tin" + }, + { + "id": 22, + "name": "Nguyễn Văn Quang", + "username": "quangnv", + "yob": 1997, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "An toàn thông tin" + }, + { + "id": 23, + "name": "Ninh Chí Hướng", + "username": "huongnc", + "yob": 2002, + "sex": "Nam", + "school": "Học viện Công nghệ Bưu chính viễn thông", + "major": "An toàn thông tin" + }, + { + "id": 24, + "name": "Ninh Văn Nghĩa", + "username": "nghianv", + "yob": 2001, + "sex": "Nam", + "school": "Đại Học Bách Khoa Hà Nội", + "major": "Khoa học máy tính" + }, + { + "id": 25, + "name": "Phạm Anh Đức", + "username": "ducpa", + "yob": 2001, + "sex": "Nam", + "school": "Đại học Bách Khoa Hà Nội", + "major": "Toán ứng dụng và tin học" + }, + { + "id": 26, + "name": "Phạm Duy Cương", + "username": "cuongpd", + "yob": 1997, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "Công nghệ điện tử" + }, + { + "id": 27, + "name": "Phạm Hồng Thanh", + "username": "thanhph", + "yob": 1998, + "sex": "Nam", + "school": "Swinburne University", + "major": "Phát triển phần mềm" + }, + { + "id": 28, + "name": "Phạm Thị Khánh Linh", + "username": "linhptk", + "yob": 2002, + "sex": "Nữ", + "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", + "major": "Mạng máy tính và truyền thông dữ liệu" + }, + { + "id": 29, + "name": "Phạm Văn Tới", + "username": "toipv", + "yob": 2002, + "sex": "Nam", + "school": "Học viện Công nghệ Bưu chính viễn thông", + "major": "Công nghệ thông tin ứng dụng phần mềm" + }, + { + "id": 30, + "name": "Trần Đức Mạnh", + "username": "manhtd", + "yob": 1998, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "Bảo mật thông tin" + }, + { + "id": 31, + "name": "Trần Mạnh Dũng", + "username": "dungtm", + "yob": 2001, + "sex": "Nam", + "school": "Học viện Công nghệ Bưu chính Viễn thông", + "major": "Điện tử viễn thông" + }, + { + "id": 32, + "name": "Trần Minh Dương", + "username": "duongtm", + "yob": 2002, + "sex": "Nam", + "school": "Đại học Công nghệ - Đại học Quốc gia Hà Nội", + "major": "Mạng máy tính và truyền thông dữ liệu" + }, + { + "id": 33, + "name": "Trần Xuân Phú", + "username": "phutx", + "yob": 2001, + "sex": "Nam", + "school": "Trường Đại học Công nghệ thông tin - ĐHQG Tp.Hồ chí Minh", + "major": "Khoa học máy tính" + }, + { + "id": 34, + "name": "Vũ Hoàng Long", + "username": "longvh", + "yob": 2001, + "sex": "Nam", + "school": "Đại học Bách Khoa Hà Nội", + "major": "Khoa học máy tính" + }, + { + "id": 35, + "name": "Vũ Minh Hiếu", + "username": "hieuvm", + "yob": 2000, + "sex": "Nam", + "school": "Đại học CNTT, cơ khí & quang học St.Petersburg LB Nga", + "major": "Kỹ thuật phần mềm" } -] \ No newline at end of file + ] \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/ansible/collections/ansible_collections/.gitkeep b/1. Containerization/Le Van Chien/app/project/__init__.py similarity index 100% rename from 1. Containerization/Le Van Chien/ansible/collections/ansible_collections/.gitkeep rename to 1. Containerization/Le Van Chien/app/project/__init__.py diff --git a/1. Containerization/Le Van Chien/app/project/__pycache__/__init__.cpython-39.pyc b/1. Containerization/Le Van Chien/app/project/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 000000000..2455c354a Binary files /dev/null and b/1. Containerization/Le Van Chien/app/project/__pycache__/__init__.cpython-39.pyc differ diff --git a/1. Containerization/Le Van Chien/app/project/__pycache__/api.cpython-39.pyc b/1. Containerization/Le Van Chien/app/project/__pycache__/api.cpython-39.pyc new file mode 100644 index 000000000..9697e9a93 Binary files /dev/null and b/1. Containerization/Le Van Chien/app/project/__pycache__/api.cpython-39.pyc differ diff --git a/1. Containerization/Le Van Chien/app/project/__pycache__/database.cpython-39.pyc b/1. Containerization/Le Van Chien/app/project/__pycache__/database.cpython-39.pyc new file mode 100644 index 000000000..86dbf145d Binary files /dev/null and b/1. Containerization/Le Van Chien/app/project/__pycache__/database.cpython-39.pyc differ diff --git a/1. Containerization/Le Van Chien/app/project/api.py b/1. Containerization/Le Van Chien/app/project/api.py new file mode 100644 index 000000000..ef6d44fb2 --- /dev/null +++ b/1. Containerization/Le Van Chien/app/project/api.py @@ -0,0 +1,40 @@ +from flask import Flask, request +from flask_cors import CORS, cross_origin +from bson import json_util + +def create_app(db): + app = Flask('app') + cors = CORS(app) + + @app.route('/people/', methods = ['GET']) + def getAll(): + attendees = json_util.dumps(db.attendees.find({})) + return attendees + + @app.route('/people/', methods = ['GET']) + def getByID(num): + return json_util.dumps(db.attendees.find({"id": num})) + + @app.route('/people/', methods = ['GET']) + def getByUsername(username): + return json_util.dumps(db.attendees.find({"username": username})) + + @app.route('/people/delete/', methods = ['DELETE']) + def delete(username): + db.attendees.delete_one({'username': username}) + return json_util.dumps({'message': f'Resource with username {username} deleted'}) + + + @app.route('/people/create/', methods = ['PUT']) + def create(): + data = request.get_json() + db.attendees.insert_one(data) + return json_util.dumps({'message': 'Resource with username {} created'.format(data['username'])}) + + @app.route('/people/update/', methods = ['PUT']) + def update(username): + data = request.get_json() + db.attendees.update_one({'username':username}, {'$set': data}) + return json_util.dumps({'message': 'Resource with username {} updated'.format(username)}) + + return app \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/app/project/database.py b/1. Containerization/Le Van Chien/app/project/database.py new file mode 100644 index 000000000..16f8a4d7c --- /dev/null +++ b/1. Containerization/Le Van Chien/app/project/database.py @@ -0,0 +1,13 @@ +from pymongo import MongoClient +import json + +def create_db(): + client = MongoClient('mongodb://db:27017') + client.drop_database('attendee') + db = client.attendee + if 'attendees' not in db.list_collection_names(): + with open('data/attendees.json') as f: + data = json.load(f) + db.attendees.insert_many(data) + + return db \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/app/tests/__init__.py b/1. Containerization/Le Van Chien/app/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/1. Containerization/Le Van Chien/app/tests/__pycache__/__init__.cpython-38.pyc b/1. Containerization/Le Van Chien/app/tests/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 000000000..052f0cbd9 Binary files /dev/null and b/1. Containerization/Le Van Chien/app/tests/__pycache__/__init__.cpython-38.pyc differ diff --git a/1. Containerization/Le Van Chien/app/tests/__pycache__/conftest.cpython-38-pytest-7.3.1.pyc b/1. Containerization/Le Van Chien/app/tests/__pycache__/conftest.cpython-38-pytest-7.3.1.pyc new file mode 100644 index 000000000..88e76da64 Binary files /dev/null and b/1. Containerization/Le Van Chien/app/tests/__pycache__/conftest.cpython-38-pytest-7.3.1.pyc differ diff --git a/1. Containerization/Le Van Chien/app/tests/__pycache__/test_api.cpython-38-pytest-7.3.1.pyc b/1. Containerization/Le Van Chien/app/tests/__pycache__/test_api.cpython-38-pytest-7.3.1.pyc new file mode 100644 index 000000000..02b91efbf Binary files /dev/null and b/1. Containerization/Le Van Chien/app/tests/__pycache__/test_api.cpython-38-pytest-7.3.1.pyc differ diff --git a/1. Containerization/Le Van Chien/app/tests/conftest.py b/1. Containerization/Le Van Chien/app/tests/conftest.py new file mode 100644 index 000000000..5dc70c2f4 --- /dev/null +++ b/1. Containerization/Le Van Chien/app/tests/conftest.py @@ -0,0 +1,12 @@ +import pytest +import json +from mongomock import MongoClient + +@pytest.fixture +def db(): + client = MongoClient() + db = client.attendee + with open('data/attendees.json') as f: + data = json.load(f) + db.attendees.insert_many(data) + yield db \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/app/tests/test_api.py b/1. Containerization/Le Van Chien/app/tests/test_api.py new file mode 100644 index 000000000..20798462f --- /dev/null +++ b/1. Containerization/Le Van Chien/app/tests/test_api.py @@ -0,0 +1,126 @@ +import json +from project.api import create_app + +GET_ALL = '/people/' +GET_BY_USERNAME = '/people/chienlv' +GET_BY_ID = '/people/11' +PUT_NEW_DATA = 'people/create/' +UPDATE_DATA = 'people/update/chienlv' +DELETE_DATA = 'people/delete/chienlv' + +def test_getByUsername(db): + app = create_app(db) + response = app.test_client().get(GET_BY_USERNAME) + data = json.loads(response.data.decode('utf-8')) + + assert len(data) == 1 + assert data[0]['id'] == 11 + assert response.status_code == 200 + +def test_getAll(db): + app = create_app(db) + response = app.test_client().get(GET_ALL) + data = json.loads(response.data.decode('utf-8')) + + assert type(data) is list + assert type(data[0]) is dict + assert data[10]['id'] == 11 + assert data[10] ['username'] == 'chienlv' + assert response.status_code == 200 + +def test_getByID(db): + app = create_app(db) + response = app.test_client().get(GET_BY_ID) + data = json.loads(response.data.decode('utf-8')) + + assert type(data[0]) is dict + assert len(data) == 1 + assert data[0]['username'] == 'chienlv' + assert response.status_code == 200 + +def test_create(db): + app = create_app(db) + client = app.test_client() + + def getAll(client): + response = client.get(GET_ALL) + data = json.loads(response.data.decode('utf-8')) + return data + + dataBeforePUT = getAll(client) + + + newData = { + 'id': 50, + 'name': "Lorem Ipsum", + 'username': 'li', + 'yob': 2002, + 'sex': 'nam', + 'school': 'Vietnam National University', + 'major': 'School of Aerospace Engineering' + } + + headers = { + 'Content-Type': 'application/json' + } + + response = client.put(PUT_NEW_DATA, data=json.dumps(newData), headers=headers) + + + dataAfterPUT = getAll(client) + + assert len(dataAfterPUT) == len(dataBeforePUT) + 1 + assert dataAfterPUT[-1]['id'] == 50 + assert dataAfterPUT[-1]['username'] == 'li' + assert response.status_code == 200 + +def test_update(db): + app = create_app(db) + client = app.test_client() + + def getOne(client): + response = client.get(GET_BY_USERNAME) + data = json.loads(response.data.decode('utf-8')) + return data + + dataBeforePUT = getOne(client) + + + newData = { + 'school': 'Vietnam National University', + 'major': 'School of Aerospace Engineering' + } + + headers = { + 'Content-Type': 'application/json' + } + + response = client.put(UPDATE_DATA, data=json.dumps(newData), headers=headers) + + + dataAfterPUT = getOne(client) + + assert dataAfterPUT[0]['username'] == 'chienlv' + assert dataAfterPUT[0]['major'] == 'School of Aerospace Engineering' + assert response.status_code == 200 + + +def test_delete(db): + app = create_app(db) + client = app.test_client() + + def getAll(client): + response = client.get(GET_ALL) + data = json.loads(response.data.decode('utf-8')) + return data + + dataBeforePUT = getAll(client) + + + response = client.delete(DELETE_DATA) + + + dataAfterPUT = getAll(client) + + assert len(dataAfterPUT) == len(dataBeforePUT) -1 + assert response.status_code == 200 \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/app/tests/test_requirements.txt b/1. Containerization/Le Van Chien/app/tests/test_requirements.txt new file mode 100644 index 000000000..ece56fe24 --- /dev/null +++ b/1. Containerization/Le Van Chien/app/tests/test_requirements.txt @@ -0,0 +1,3 @@ +pytest +mongomock +-r ../requirements.txt \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/docker-compose.yml b/1. Containerization/Le Van Chien/docker-compose.yml index e37c4b6e0..f458bfe76 100644 --- a/1. Containerization/Le Van Chien/docker-compose.yml +++ b/1. Containerization/Le Van Chien/docker-compose.yml @@ -4,7 +4,8 @@ networks: driver: bridge services: nginx: - image: nginx:1.22.0-alpine + build: ./nginx + container_name: web ports: - "8080:80" depends_on: @@ -16,6 +17,7 @@ services: - net app: build: ./app + container_name: app depends_on: - db networks: @@ -28,6 +30,7 @@ services: - "5000:5000" db: image: mongo:5.0 + container_name: db ports: - "27017:27017" networks: diff --git a/1. Containerization/Le Van Chien/nginx/Dockerfile b/1. Containerization/Le Van Chien/nginx/Dockerfile new file mode 100644 index 000000000..4058d5d69 --- /dev/null +++ b/1. Containerization/Le Van Chien/nginx/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx:1.22.0-alpine +COPY ./nginx.conf /etc/nginx/nginx.conf +COPY ./static /var/www/html \ No newline at end of file diff --git a/1. Containerization/Le Van Chien/nginx/nginx.conf b/1. Containerization/Le Van Chien/nginx/nginx.conf index a3ca6bfb5..f8f314cdf 100644 --- a/1. Containerization/Le Van Chien/nginx/nginx.conf +++ b/1. Containerization/Le Van Chien/nginx/nginx.conf @@ -1,5 +1,9 @@ events {} http { + upstream api_server { + server api:5000; + # server app2:5000; + } server { listen 80; location / { @@ -7,5 +11,9 @@ http { root /var/www/html; index index.html; } + + location /people/ { + proxy_pass http://api_server; + } } } diff --git a/1. Containerization/Le Van Chien/nginx/static/index.html b/1. Containerization/Le Van Chien/nginx/static/index.html index e7a11b1f9..52f2dfe25 100644 --- a/1. Containerization/Le Van Chien/nginx/static/index.html +++ b/1. Containerization/Le Van Chien/nginx/static/index.html @@ -16,6 +16,7 @@

VDT Cloud Attendee

ID Họ và tên + Username Năm sinh Giới tính Trường @@ -23,7 +24,8 @@

VDT Cloud Attendee

- + + @@ -32,7 +34,9 @@

VDT Cloud Attendee

- +
+ +
\ No newline at end of file diff --git a/1. Containerization/Le Van Chien/nginx/static/script.js b/1. Containerization/Le Van Chien/nginx/static/script.js index 2c820a022..dd082fe72 100644 --- a/1. Containerization/Le Van Chien/nginx/static/script.js +++ b/1. Containerization/Le Van Chien/nginx/static/script.js @@ -2,27 +2,185 @@ const searchBtn = document.querySelector('#search-btn'); searchBtn.onclick = function() { const id = document.querySelector('#id-input').value; + const username = document.querySelector('#username-input').value; - fetch('http://localhost:5000/people/' + id) - .then(response => response.json()) - .then(data => loadHTMLTable(data)); + if (username === "") { + fetch('/people/' + id) + .then(response => response.json()) + .then(data => loadHTMLTable(data)); + } + else { + fetch('/people/' + username) + .then(response => response.json()) + .then(data => loadHTMLTable(data)); + } } + +function sendDeleteRequest(username, btn) { + fetch('/people/delete/' + username, { + method: 'DELETE' + }) + .then(response => response.json()) + .then(result => { + console.log(result.message); + row = btn.parentNode.parentNode; + row.parentNode.removeChild(row); + }) + .catch(error => { + console.error(error); + // Handle errors + }); +} + +// Attach event listeners to the delete buttons +document.querySelector('table tbody').addEventListener('click', function(event) { + if (event.target.className === "delete-row-btn") { + sendDeleteRequest(event.target.dataset.user, event.target); + } + if (event.target.className === "cancel-btn") { + row = event.target.parentNode.parentNode; + row.parentNode.removeChild(row); + } + if (event.target.className === "submit-btn") { + addNewAttendee(event.target.parentNode.parentNode) + } + + if (event.target.className === 'edit-row-btn') { + getNewData(event.target.parentNode.parentNode, event.target.dataset.user) + } + + if (event.target.className === 'change-btn') { + change(event.target.parentNode.parentNode, event.target.dataset.user); + event.target.parentNode.innerHTML = ""; + } + +}); + + +// ADD + +addBtn = document.querySelector('#add-btn'); + +addBtn.onclick = function() { + const table = document.querySelector('table tbody'); + let tableHtml = ""; + tableHtml += ""; + tableHtml += ``; + tableHtml += ``; + tableHtml += ``; + tableHtml += ``; + tableHtml += ``; + tableHtml += ``; + tableHtml += ``; + tableHtml += ``; + tableHtml += ``; + tableHtml += ""; + + table.innerHTML += tableHtml; +} + + +function addNewAttendee(row) { + var id = row.querySelector('#new-id').value; + const newAttendee = { + id: row.querySelector('#new-id').value, + name: row.querySelector('#new-name').value, + username: row.querySelector('#new-username').value, + yob: row.querySelector('#new-yob').value, + sex: row.querySelector('#new-sex').value, + school: row.querySelector('#new-school').value, + major: row.querySelector('#new-major').value + }; + + + fetch('/people/create/', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(newAttendee), + }) + .then(response => response.json()) + .then(result => { + console.log(result.message); + row.parentNode.removeChild(row); + }) +} + +// update //////////// + +function getNewData(row, username) { + const cells = row.querySelectorAll('td'); // Get all elements within the row + cells.forEach((cell, index) => { + const value = cell.textContent; + if (index == 0) { + cell.innerHTML = `