Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Webhook Utility #12

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ services:
- MYSQL_DATABASE=pesticide_docker
- MYSQL_USER=test_user
- MYSQL_PASSWORD=test_user_password
- MYSQL_ROOT_PASSWORD=ROOT_PASSWORD
- MYSQL_ROOT_PASSWORD=
volumes:
- /home/pesticide-data:/var/lib/mysql
expose:
Expand All @@ -27,12 +27,15 @@ services:
backend:
restart: always
container_name: pesticide_backend
command: bash -c "cd ./src && python check_db.py --service-name db --ip db --port 3306 && python manage.py collectstatic --noinput && python manage.py makemigrations pesticide_app && python manage.py makemigrations && python manage.py migrate && daphne -b 0.0.0.0 -p 8000 pesticide.asgi:application"
command: bash -c "cd ./src && python check_db.py --service-name db --ip db --port 3306 && python manage.py collectstatic --noinput && daphne -b 0.0.0.0 -p 8000 pesticide.asgi:application"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not commit this modified docker-compose file. The modifications made were only for easy development, and cannot be used in a production setup.

build:
context: ./pesticide_backend/
dockerfile: Dockerfile
volumes:
- ./pesticide_backend:/backend
- type: bind
source: ./pesticide_backend
target: /backend
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this necessary?

read_only: false
expose:
- "8000"
depends_on:
Expand All @@ -43,14 +46,16 @@ services:

frontend:
container_name: pesticide_frontend
command: npm run build
command: npm start
build:
context: ./pesticide_frontend/
dockerfile: Dockerfile
volumes:
- ./pesticide_frontend:/frontend
expose:
- "3000"
ports:
- 3000:3000
stdin_open: true
depends_on:
- backend
Expand Down
14 changes: 11 additions & 3 deletions nginx/nginx-proxy.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ upstream redis-server {
server backend:8000 fail_timeout=0;
}

upstream frontend-server {
ip_hash;
server frontend:3000 fail_timeout=0;
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just like the docker-compose file, modifications made to this file were only meant for development setup, and are not meant to be committed.

server {
listen 8080;

Expand Down Expand Up @@ -44,9 +49,12 @@ server {
proxy_no_cache 1;
}

# location / {
# root /var/www/frontend;
# try_files $uri $uri/ /index.html;
# }

location / {
root /var/www/frontend;
try_files $uri $uri/ /index.html;
proxy_pass http://frontend-server;
}

}
2 changes: 1 addition & 1 deletion pesticide_backend/src/pesticide/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
ALLOWED_HOSTS = ['*']
PAGE_SIZE = BASE_CONFIGURATION["pagination"]["page_size"]
FRONTEND_URL = BASE_CONFIGURATION["frontend"]["url"]

FLASK_TOKEN = BASE_CONFIGURATION["flaskToken"]["token"]
# Application definition

INSTALLED_APPS = [
Expand Down
2 changes: 2 additions & 0 deletions pesticide_backend/src/pesticide_app/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
EmailSubscription,
Reactor,
Emoticon,
WebhookDetails,
)

admin.site.register(User)
Expand All @@ -25,3 +26,4 @@
admin.site.register(EmailSubscription)
admin.site.register(Reactor)
admin.site.register(Emoticon)
admin.site.register(WebhookDetails)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .user import UserSerializer, UsersIssueTallySerializer, UserStatusSerializer, UserLoggedInSerializer
from .user import UserSerializer, UsersIssueTallySerializer, UserStatusSerializer, UserLoggedInSerializer, UserEnrollementNoSerializer
from .project import ProjectSerializer, ProjectIconSerializer, ProjectNameSlugSerializer, ProjectMembersSerializer, ProjectIssueStatusSerializer
from .issue import IssueSerializer, IssueSearchSerializer, IssueImageSerializer, IssueStatusSerializer, IssueStatusTallySerializer
from .comment import CommentSerializer
Expand All @@ -7,3 +7,4 @@
from .email_subscription import EmailSubscriptionSerializer
from .emoticon import EmoticonSerializer
from .reactor import ReactorSerializer
from .webhook_details import WebhookFlaskSerializer, WebhookSerializer, WebhookDetailsSerializer
5 changes: 5 additions & 0 deletions pesticide_backend/src/pesticide_app/api/serializers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ class Meta:
model = User
read_only_fields = ('is_master', )
fields = ('username', 'id', 'is_master')

class UserEnrollementNoSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','enrollment_number', 'name','display_picture')
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from django.core.serializers import serialize
from rest_framework import serializers
from pesticide_app.models import WebhookDetails

class WebhookSerializer(serializers.ModelSerializer):

class Meta:
model = WebhookDetails
fields = '__all__'

class WebhookFlaskSerializer(serializers.ModelSerializer):

class Meta:
model = WebhookDetails
fields = ['name','repository_name','ssh_url','path','secret','branch','identifier']

class WebhookDetailsSerializer(serializers.ModelSerializer):

class Meta:
model = WebhookDetails
fields = ['id','name','repository_name','ssh_url','path','branch','identifier','project','creator','timestamp']




3 changes: 3 additions & 0 deletions pesticide_backend/src/pesticide_app/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@
router.register(r'user_status', UserStatusViewset, basename='user_status')
router.register(r'emoticons', EmoticonViewSet, basename='emoticons')
router.register(r'comment_reactions', ReactorViewSet, basename='comment_reactions')
router.register(r'webhook',WebhookViewSet, basename='webhook')
urlpatterns = router.urls

urlpatterns += [
url(r'topdebuggers', TopDebuggersView.as_view()),
url(r'tag_colors', TagColorsView.as_view()),
url(r'issue_status_colors', IssueStatusColorsView.as_view()),
url(r'search', SearchView.as_view()),
path('webhook_flask/<str:pk>/details',WebhookFlaskView.as_view()),
path('webhook_details/<int:pk>/',WebhookDetailsView.as_view()),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 3.1.1 on 2022-02-18 12:58

import datetime
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('pesticide_app', '0011_auto_20210105_2148'),
]

operations = [
migrations.CreateModel(
name='WebhookDetails',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, unique=True)),
('repository_name', models.CharField(max_length=500)),
('ssh_url', models.CharField(max_length=1000)),
('path', models.CharField(max_length=1000)),
('secret', models.CharField(max_length=1000)),
('branch', models.CharField(max_length=1000)),
('identifier', models.CharField(max_length=100, unique=True)),
('timestamp', models.DateTimeField(blank=True, default=datetime.datetime.now, null=True)),
('creator', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='webhook_creator', to=settings.AUTH_USER_MODEL)),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='webhooks', to='pesticide_app.project')),
],
options={
'ordering': ['-timestamp'],
},
),
]
1 change: 1 addition & 0 deletions pesticide_backend/src/pesticide_app/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
from .email_subscription import EmailSubscription
from .emoticon import Emoticon
from .reactor import Reactor
from .webhookDetails import WebhookDetails
23 changes: 23 additions & 0 deletions pesticide_backend/src/pesticide_app/models/webhookDetails.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.db import models
from pesticide_app.models.project import Project
from pesticide_app.models.user import User
from datetime import datetime

class WebhookDetails(models.Model):

name = models.CharField(max_length=100, unique=True)
repository_name = models.CharField(max_length=500)
ssh_url = models.CharField(max_length=1000)
path = models.CharField(max_length=1000) #wrt omniport codebase
secret = models.CharField(max_length=1000)
branch = models.CharField(max_length=1000)
identifier = models.CharField(max_length=100, unique=True) #used to identify webhook url
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='webhooks')
creator = models.ForeignKey(User, null=True, on_delete=models.CASCADE, related_name='webhook_creator')
timestamp = models.DateTimeField(default=datetime.now, blank=True, null=True)

def __str__(self):
return self.name

class Meta:
ordering = ['-timestamp']
23 changes: 22 additions & 1 deletion pesticide_backend/src/pesticide_app/permissions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from rest_framework import permissions
from pesticide_app.models import *

from pesticide.settings import FLASK_TOKEN

class CommentorPermissions(permissions.BasePermission):
"""
Expand Down Expand Up @@ -121,3 +121,24 @@ def has_object_permission(self, request, view, obj):
return request.user in obj.project.members.all() or obj.project.creator == request.user

return False

class ProjectMemberOrAdmin(permissions.BasePermission):
"""
Allow webhook edit/add/delete access to only the members of the project and admins.
"""

def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS :
return True
if request.user in obj.project.members.all() or request.user.is_master:
return True
return obj.creator

class IsFlaskRequest(permissions.BasePermission):
"""
Verify Flask user with token authentication.
"""
def has_permission(self, request, view):
if request.method == 'GET' :
return request.headers['Token'] == FLASK_TOKEN
return False
3 changes: 3 additions & 0 deletions pesticide_backend/src/pesticide_app/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@
from .search.unity_search import SearchView
from .emoticon.emoticon import EmoticonViewSet
from .comment_reaction.reaction import ReactorViewSet
from .webhook.webhook_details import WebhookDetailsView
from .webhook.webhook_flask import WebhookFlaskView
from .webhook.webhook import WebhookViewSet
16 changes: 16 additions & 0 deletions pesticide_backend/src/pesticide_app/views/webhook/webhook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from pesticide_app.permissions import ProjectMemberOrAdmin
from rest_framework.authentication import SessionAuthentication
from pesticide_app.api.serializers import WebhookSerializer
from pesticide_app.models import WebhookDetails


class WebhookViewSet(viewsets.ModelViewSet):
serializer_class = WebhookSerializer
queryset = WebhookDetails.objects.all()
permission_classes = [IsAuthenticated & ProjectMemberOrAdmin ]
authentication_classes = [SessionAuthentication, ]

def perform_create(self,serializer):
serializer.save(creator = self.request.user)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from pesticide_app.permissions import ReadOnlyPermissions
from rest_framework.authentication import SessionAuthentication
from pesticide_app.api.serializers import WebhookDetailsSerializer
from pesticide_app.models import Project


class WebhookDetailsView(APIView):
permission_classes = [IsAuthenticated & ReadOnlyPermissions]
authentication_classes = [SessionAuthentication, ]

def get(self, request, pk, format = None):
project = Project.objects.get(id=pk)
webhook_data = WebhookDetailsSerializer(project.webhooks.all(),many=True)
return Response(webhook_data.data)
21 changes: 21 additions & 0 deletions pesticide_backend/src/pesticide_app/views/webhook/webhook_flask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.http import HttpResponse
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused imports.

from django.forms.models import model_to_dict
from django.http import JsonResponse
from rest_framework.views import APIView
from pesticide_app.models import WebhookDetails
from pesticide_app.permissions import IsFlaskRequest

class WebhookFlaskView(APIView):
permission_classes = [IsFlaskRequest]

def get(self, request, pk, format=None):
try:
webhook = WebhookDetails.objects.get(identifier = pk)
return JsonResponse(model_to_dict(webhook))
except:
return HttpResponse("No matching query")

def get_permissions(self):
if self.request.method == 'GET':
self.permission_classes = [IsFlaskRequest]
return super(WebhookFlaskView, self).get_permissions()
2 changes: 1 addition & 1 deletion pesticide_frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ FROM node:10.18-alpine
WORKDIR /frontend
COPY package.json package-lock.json ./
RUN npm install
RUN npm install [email protected] -g
# RUN npm install [email protected] -g
COPY . ./
Loading