Skip to content

Commit f6c0f95

Browse files
authored
Merge pull request #63 from Code4GovTech/dev
Merging Dev With Main
2 parents 8d1f6f0 + ef4df9f commit f6c0f95

14 files changed

+392
-185
lines changed

.github/workflows/build-and-push.yaml

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Build and Push Docker Image
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- dev
8+
release:
9+
types: [published]
10+
env:
11+
REGISTRY: ghcr.io
12+
IMAGE_NAME: ${{ github.repository }}
13+
14+
jobs:
15+
build-and-push:
16+
runs-on: ubuntu-latest
17+
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
18+
permissions:
19+
contents: read
20+
packages: write
21+
steps:
22+
23+
- name: Checkout code
24+
uses: actions/checkout@v2
25+
26+
- name: Set up Docker Buildx
27+
uses: docker/setup-buildx-action@v2
28+
29+
- name: Log in to the Container registry
30+
uses: docker/login-action@v3
31+
with:
32+
registry: ${{ env.REGISTRY }}
33+
username: ${{ github.actor }}
34+
password: ${{ secrets.GITHUB_TOKEN }}
35+
36+
- name: Extract metadata (tags, labels) for Docker
37+
id: meta
38+
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
39+
with:
40+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
41+
tags: |
42+
# minimal
43+
type=pep440,pattern={{version}},value=${{ github.ref_name }},enable=${{ github.event_name == 'release' }}
44+
# branch event
45+
type=ref,event=branch
46+
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
47+
48+
- name: Build and Push Docker image
49+
uses: docker/build-push-action@v4
50+
with:
51+
# build-args:
52+
context: .
53+
push: true
54+
cache-from: type=gha
55+
cache-to: type=gha,mode=max
56+
tags: ${{ steps.meta.outputs.tags }}
57+
labels: ${{ steps.meta.outputs.labels }}

.github/workflows/ci.yml

+8
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ jobs:
6565
SUPABASE_URL: ${{ vars[format('APP_{0}_SUPABASE_URL', needs.set_vars.outputs.APP_ENV)] }}
6666
SUPABASE_KEY: ${{ secrets[format('APP_{0}_SUPABASE_KEY', needs.set_vars.outputs.APP_ENV)] }}
6767
SECRET_KEY: ${{ secrets[format('APP_{0}_SECRET_KEY', needs.set_vars.outputs.APP_ENV)] }}
68+
POSTGRES_DB_HOST: ${{ secrets[format('APP_{0}_POSTGRES_DB_HOST', needs.set_vars.outputs.APP_ENV)] }}
69+
POSTGRES_DB_NAME: ${{ secrets[format('APP_{0}_POSTGRES_DB_NAME', needs.set_vars.outputs.APP_ENV)] }}
70+
POSTGRES_DB_USER: ${{ secrets[format('APP_{0}_POSTGRES_DB_USER', needs.set_vars.outputs.APP_ENV)] }}
71+
POSTGRES_DB_PASS: ${{ secrets[format('APP_{0}_POSTGRES_DB_PASS', needs.set_vars.outputs.APP_ENV)] }}
6872
steps:
6973
- name: Checkout code
7074
uses: actions/checkout@v2
@@ -87,6 +91,10 @@ jobs:
8791
echo "SUPABASE_URL=${SUPABASE_URL}" >> .env
8892
echo "SUPABASE_KEY=${SUPABASE_KEY}" >> .env
8993
echo "SECRET_KEY=${SECRET_KEY}" >> .env
94+
echo "POSTGRES_DB_HOST=${POSTGRES_DB_HOST}" >> .env
95+
echo "POSTGRES_DB_NAME=${POSTGRES_DB_NAME}" >> .env
96+
echo "POSTGRES_DB_USER=${POSTGRES_DB_USER}" >> .env
97+
echo "POSTGRES_DB_PASS=${POSTGRES_DB_PASS}" >> .env
9098
mv .env ${{ env.DOT_ENV_FILE_NAME }}
9199
92100
- name: Copy env file to DEV Server

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "shared_migrations"]
2+
path = shared_migrations
3+
url = https://github.com/Code4GovTech/shared-models-migrations.git

Dockerfile

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@ FROM python:3.12-slim
55
WORKDIR /app
66

77
# Copy the current directory contents into the container at /app
8+
9+
RUN apt-get update && \
10+
apt-get install -y --no-install-recommends git openssh-client && \
11+
rm -rf /var/lib/apt/lists/*
12+
813
COPY . /app
914

15+
RUN --mount=type=ssh git submodule update --init --recursive
16+
1017
# Install any needed packages specified in requirements.txt
1118
RUN pip install --no-cache-dir -r requirements.txt
1219

1320
# Make port 5000 available to the world outside this container
14-
EXPOSE 7000
21+
EXPOSE 5000
1522

1623
# Define environment variable
1724
ENV FLASK_APP=wsgi.py
1825
ENV FLASK_RUN_HOST=0.0.0.0
1926

2027
# Run the application
21-
CMD ["flask", "run", "--host=0.0.0.0", "--port=7000"]
22-
28+
CMD ["flask", "run"]

app.py

+46-86
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
from flask import Flask, jsonify,request,url_for
2-
from db import SupabaseInterface
32
from collections import defaultdict
43
from flasgger import Swagger
54
import re,os,traceback
5+
# from query import PostgresORM
66
from utils import *
77
from flask_cors import CORS,cross_origin
88
from v2_app import v2
9+
from flask_sqlalchemy import SQLAlchemy
10+
from models import db
11+
from shared_migrations.db import get_postgres_uri
12+
from shared_migrations.db.dmp_api import DmpAPIQueries
13+
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
14+
from sqlalchemy.orm import sessionmaker
15+
from sqlalchemy.pool import NullPool
16+
917

1018

1119
app = Flask(__name__)
1220
CORS(app,supports_credentials=True)
1321

1422

23+
app.config['SQLALCHEMY_DATABASE_URI'] = get_postgres_uri()
24+
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
25+
26+
# Initialize Async SQLAlchemy
27+
engine = create_async_engine(app.config['SQLALCHEMY_DATABASE_URI'], echo=False,poolclass=NullPool)
28+
async_session = sessionmaker(autocommit=False, autoflush=False, bind=engine, class_=AsyncSession)
29+
30+
31+
db.init_app(app)
32+
1533
Swagger(app)
1634

1735
GITHUB_TOKEN =os.getenv('GITHUB_TOKEN')
@@ -45,67 +63,12 @@ def greeting():
4563

4664

4765

48-
49-
@app.route('/get-data', methods=['GET'])
50-
@cross_origin(supports_credentials=True)
51-
@require_secret_key
52-
def get_data():
53-
"""
54-
Fetch data from Supabase.
55-
---
56-
responses:
57-
200:
58-
description: Data fetched successfully
59-
schema:
60-
type: array
61-
items:
62-
type: object
63-
500:
64-
description: Error fetching data
65-
schema:
66-
type: object
67-
properties:
68-
error:
69-
type: string
70-
"""
71-
try:
72-
response = SupabaseInterface().get_instance().client.table('dmp_pr_updates').select('*').execute()
73-
data = response.data
74-
return jsonify(data)
75-
except Exception as e:
76-
return jsonify({'error': str(e)}), 200
77-
78-
79-
80-
@app.route('/v1/issues', methods=['GET'])
81-
@require_secret_key
82-
def v1get_issues():
83-
try:
84-
response = SupabaseInterface().get_instance().client.table('dmp_issue_updates').select('*').execute()
85-
data = response.data
86-
87-
#group data based on issues
88-
grouped_data = defaultdict(list)
89-
for record in data:
90-
issue_url = record['issue_url']
91-
grouped_data[issue_url].append({
92-
'id': record['id'],
93-
'name': record['body_text']
94-
})
95-
96-
result = [{'issue_url': issue_url, 'issues': issues} for issue_url, issues in grouped_data.items()]
97-
grouped_data = group_by_owner(result)
98-
return jsonify(grouped_data)
99-
100-
except Exception as e:
101-
error_traceback = traceback.format_exc()
102-
return jsonify({'error': str(e), 'traceback': error_traceback}), 200
10366

10467

10568
@app.route('/issues', methods=['GET'])
106-
@cross_origin(supports_credentials=True)
107-
@require_secret_key
108-
def get_issues():
69+
# @cross_origin(supports_credentials=True)
70+
# @require_secret_key
71+
async def get_issues():
10972
"""
11073
Fetch all issues and group by owner.
11174
---
@@ -127,30 +90,28 @@ def get_issues():
12790
type: string
12891
"""
12992
try:
130-
# Fetch all issues with their details
131-
response = SupabaseInterface().get_instance().client.table('dmp_orgs').select('*, dmp_issues(*)').execute()
132-
res = []
133-
134-
for org in response.data:
135-
obj = {}
136-
issues = org['dmp_issues']
137-
obj['org_id'] = org['id']
138-
obj['org_name'] = org['name']
139-
renamed_issues = [{"id": issue["id"], "name": issue["title"]} for issue in issues]
140-
obj['issues'] = renamed_issues
141-
142-
res.append(obj)
143-
144-
return jsonify({"issues": res})
93+
# Fetch all issues with their details
94+
print('inside get all issues')
95+
data = await DmpAPIQueries.get_issue_query(async_session)
96+
response = []
97+
98+
for result in data:
99+
response.append({
100+
'org_id': result.org_id,
101+
'org_name': result.org_name,
102+
'issues': result.issues
103+
})
104+
105+
return jsonify({"issues": response})
145106

146107
except Exception as e:
147108
error_traceback = traceback.format_exc()
148109
return jsonify({'error': str(e), 'traceback': error_traceback}), 500
149110

150111
@app.route('/issues/<owner>', methods=['GET'])
151-
@cross_origin(supports_credentials=True)
152-
@require_secret_key
153-
def get_issues_by_owner(owner):
112+
# @cross_origin(supports_credentials=True)
113+
# @require_secret_key
114+
async def get_issues_by_owner(owner):
154115
"""
155116
Fetch organization details by owner's GitHub URL.
156117
---
@@ -190,16 +151,15 @@ def get_issues_by_owner(owner):
190151
description: Error message
191152
"""
192153
try:
193-
# Construct the GitHub URL based on the owner parameter
194-
org_link = f"https://github.com/{owner}"
195-
154+
196155
# Fetch organization details from dmp_orgs table
197-
response = SupabaseInterface().get_instance().client.table('dmp_orgs').select('name', 'description').eq('name', owner).execute()
198-
199-
if not response.data:
156+
response = await DmpAPIQueries.get_issue_owner(async_session, owner)
157+
if not response:
200158
return jsonify({'error': "Organization not found"}), 404
201-
202-
return jsonify(response.data)
159+
160+
orgs_dict = [org.to_dict() for org in response]
161+
162+
return jsonify(orgs_dict)
203163

204164
except Exception as e:
205165
error_traceback = traceback.format_exc()
@@ -243,7 +203,7 @@ def get_issues_by_owner_id(owner, issue):
243203
"""
244204
try:
245205
print('inside get issues')
246-
SUPABASE_DB = SupabaseInterface().get_instance()
206+
SUPABASE_DB = DmpAPIQueries.get_instance()
247207
response = SUPABASE_DB.client.table('dmp_issue_updates').select('*').eq('owner', owner).eq('issue_number', issue).execute()
248208
if not response.data:
249209
return jsonify({'error': "No data found"}), 200

db.py

-61
Original file line numberDiff line numberDiff line change
@@ -1,61 +0,0 @@
1-
import os, sys
2-
from typing import Any
3-
from supabase import create_client, Client
4-
from supabase.lib.client_options import ClientOptions
5-
from abc import ABC, abstractmethod
6-
7-
client_options = ClientOptions(postgrest_client_timeout=None)
8-
9-
10-
11-
class SupabaseInterface():
12-
13-
_instance = None
14-
15-
def __init__(self):
16-
if not SupabaseInterface._instance:
17-
18-
# Load environment variables
19-
from dotenv import load_dotenv
20-
load_dotenv()
21-
22-
SUPABASE_URL = os.getenv('SUPABASE_URL')
23-
SUPABASE_KEY = os.getenv('SUPABASE_KEY')
24-
self.client: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
25-
SupabaseInterface._instance = self
26-
else:
27-
SupabaseInterface._instance = self._instance
28-
29-
30-
31-
@staticmethod
32-
def get_instance():
33-
# Static method to retrieve the singleton instance
34-
if not SupabaseInterface._instance:
35-
# If no instance exists, create a new one
36-
SupabaseInterface._instance = SupabaseInterface()
37-
return SupabaseInterface._instance
38-
39-
40-
def readAll(self, table):
41-
data = self.client.table(f"{table}").select("*").execute()
42-
return data.data
43-
44-
def add_data(self, data,table_name):
45-
data = self.client.table(table_name).insert(data).execute()
46-
return data.data
47-
48-
def add_data_filter(self, data, table_name):
49-
# Construct the filter based on the provided column names and values
50-
filter_data = {column: data[column] for column in ['dmp_id','issue_number','owner']}
51-
52-
# Check if the data already exists in the table based on the filter
53-
existing_data = self.client.table(table_name).select("*").eq('dmp_id',data['dmp_id']).execute()
54-
55-
# If the data already exists, return without creating a new record
56-
if existing_data.data:
57-
return "Data already exists"
58-
59-
# If the data doesn't exist, insert it into the table
60-
new_data = self.client.table(table_name).insert(data).execute()
61-
return new_data.data

docker-compose.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ services:
44
web:
55
build: .
66
ports:
7-
- "7000:7000"
7+
- "5000:5000"
88
environment:
99
FLASK_ENV: ${FLASK_ENV:-development}
1010
SUPABASE_URL: ${SUPABASE_URL}
1111
SUPABASE_KEY: ${SUPABASE_KEY}
12-
SECRET_KEY: ${SECRET_KEY}

0 commit comments

Comments
 (0)