Fakultas Ilmu Komputer UI

Commit 01bf3008 authored by Nabila Febri Viola's avatar Nabila Febri Viola
Browse files

[CHORES] Fix conflicts

parents d19b0218 f685381c
Pipeline #48921 passed with stages
in 2 minutes and 34 seconds
from django.db import models
class Artikel(models.Model):
title = models.CharField(max_length=32)
featured_image = models.ImageField()
content = models.TextField()
posted_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return "Artikel " + self.title
class Meta:
pass
from rest_framework import serializers
from .models import Artikel
class ArtikelSerializer(serializers.ModelSerializer):
class Meta:
model = Artikel
fields = ['id', 'title', 'featured_image', 'content']
from django.test import TestCase
from rest_framework import status
from rest_framework.test import APITestCase
from .factories import ArtikelFactory
class ArtikelTests(TestCase):
def test_create(self):
article = ArtikelFactory(title="Sepuluh Manfaat Donor Darah")
self.assertEqual(str(article), "Artikel Sepuluh Manfaat Donor Darah")
class ArtikelViewTests(APITestCase):
def setUp(self):
self.article = ArtikelFactory(title="Sepuluh Manfaat Donor Darah")
def test_get_artikel_sorted_by_posted_at(self):
new_article = ArtikelFactory()
response = self.client.get('/edukasi/artikel/')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['results'][0]['title'], new_article.title)
self.assertEqual(response.data['results'][1]['title'], self.article.title)
def test_retrieve_artikel(self):
response = self.client.get('/edukasi/artikel/' + str(self.article.id) + '/')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['title'], self.article.title)
self.assertEqual(response.data['content'], self.article.content)
from rest_framework.routers import DefaultRouter
from edukasi.views import ArtikelViewSet
router = DefaultRouter()
router.register(r'artikel', ArtikelViewSet, basename='artikel')
urlpatterns = router.urls
from rest_framework import viewsets
from .serializers import ArtikelSerializer
from .models import Artikel
from main.paginations import SmallResultsSetPagination
class ArtikelViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = ArtikelSerializer
pagination_class = SmallResultsSetPagination
queryset = Artikel.objects.all().order_by('-posted_at')
from datetime import date
from django.conf import settings
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
......@@ -90,6 +91,12 @@ class Profile(models.Model):
work_email = models.EmailField(blank=True)
work_phone_no = models.CharField(max_length=20, blank=True)
@property
def age(self):
born = self.birthdate
today = date.today()
return today.year - born.year - ((today.month, today.day) < (born.month, born.day))
def __str__(self):
return f'({self.sex}, {self.blood_type})'
......
......@@ -3,3 +3,7 @@ from rest_framework.pagination import PageNumberPagination
class ExtraSmallResultsSetPagination(PageNumberPagination):
page_size = 3
class SmallResultsSetPagination(PageNumberPagination):
page_size = 6
......@@ -4,6 +4,6 @@
coverage==5.0.3
django-extensions==2.2.8
factory_boy==2.12.0
flake8-django==0.0.4
flake8-django==1.0.0
psycopg2-binary==2.8.4
Faker==4.0.1
......@@ -6,6 +6,10 @@ Django==3.0.5
django-anymail==7.0.0
djangorestframework==3.11.0
django-cors-headers==3.2.1
django-kronos==1.0
django-pandas==0.6.2
gunicorn==20.0.4
numpy==1.18.4
pandas==1.0.4
Pillow==7.1.2
django-kronos==1.0
\ No newline at end of file
XlsxWriter==1.2.9
......@@ -11,6 +11,8 @@ services:
- "8000:8000" # will be served with "master" NGINX in VM
depends_on:
- api
volumes:
- .data/media:/var/www/html/staging/api/media/
networks:
- default
- internal
......@@ -22,11 +24,16 @@ services:
restart: always
environment:
# - SECRET_KEY=another_totally_secret_random_bytes_no_one_can_touch # There's a fallback
- USE_X_FORWARDED_HOST=True
- MEDIA_URL=/staging/api/media/
- MEDIA_ROOT=/var/www/html/staging/api/media/
- DATABASE_URL=postgres://mantan:aab@db/dblood # You can try with postgres too
ports:
- "8080:8000"
depends_on:
- db
volumes:
- .data/media:/var/www/html/staging/api/media/
networks:
- default
- internal
......
......@@ -11,6 +11,8 @@ services:
- "8001:8000" # will be served with "master" NGINX in VM
depends_on:
- api
volumes:
- .data/media:/var/www/html/api/media
networks:
- default
- internal
......@@ -23,6 +25,8 @@ services:
# - STATIC_URL=https://dblood-api.netlify.com/ # This is minor setting so it doesnt appear in the Dockerfile
- ALLOWED_HOSTS=localhost;ppl2020c6.cs.ui.ac.id # Same as above
- USE_X_FORWARDED_HOST=True
- MEDIA_URL=/api/media/
- MEDIA_ROOT=/var/www/html/api/media/
- SECRET_KEY=another_totally_secret_random_bytes_no_one_can_touch # Required
- DATABASE_URL=postgres://mantan:aab@db/dblood # Will default to sqlite unless provided
# You can change the settings module, but please be aware that no
......@@ -30,6 +34,10 @@ services:
# - DJANGO_SETTINGS_MODULE=dblood.settings.production
ports:
- "8081:8000"
depends_on:
- db
volumes:
- .data/media:/var/www/html/api/media
networks:
- default
- internal
......
/**
* Implement Gatsby's Node APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/node-apis/
*/
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
// You can delete this file if you're not using it
// page.matchPath is a special key that's used for matching pages
// only on the client.
if (page.path.match(/^\/article/)) {
page.matchPath = "/article/*"
// Update the page.
createPage(page)
}
}
......@@ -17006,6 +17006,11 @@
"prop-types": "^15.6.2"
}
},
"react-animated-slider": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-animated-slider/-/react-animated-slider-2.0.0.tgz",
"integrity": "sha512-JOvLvqAfdNrYjPJWnCZbtS7d/DxSowDTFeIbaS5xUDEVJe3whgxUD6rDZ6+VI0Rhp9N03ogdpuNKlFJIoPhIyg=="
},
"react-apexcharts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.3.7.tgz",
......
......@@ -23,6 +23,7 @@
"moment": "^2.24.0",
"prop-types": "^15.7.2",
"react": "^16.13.0",
"react-animated-slider": "^2.0.0",
"react-apexcharts": "^1.3.7",
"react-bootstrap": "^1.0.0-beta.16",
"react-calendar": "^2.19.2",
......
......@@ -117,5 +117,10 @@ export const getStokDarah = () => axios.get(`/stok-darah/darah/`)
export const postAjukanAcaraDonor = data =>
axios.post("/acara-donor/pengajuan/", data, { mode: "cors" })
export const getListArtikelEdukasi = page =>
axios.get("/edukasi/artikel?page=" + page)
export const getArtikelEdukasi = id => axios.get("/edukasi/artikel/" + id)
export const getFormulirDaftarDonor = jadwalDonorId =>
axios.get("/donor/formulir-daftar/" + jadwalDonorId)
......@@ -25,7 +25,7 @@ const ModalEventDonorSubmission = ({ show, handleClose }) => {
validationSchema: EventSubmissionSchema,
})
const onSubmit = async data => {
const onSubmit = async (data) => {
const tanggal_donor = moment(data.tanggal_donor).format("YYYY-MM-DD")
const jam_mulai = moment(data.jam_mulai).format("HH:mm")
const jam_selesai = moment(data.jam_selesai).format("HH:mm")
......@@ -36,7 +36,7 @@ const ModalEventDonorSubmission = ({ show, handleClose }) => {
delete data["jam_selesai"]
const formData = new FormData()
Object.keys(data).forEach(key => {
Object.keys(data).forEach((key) => {
if (typeof data[key] != "undefined") formData.append(key, data[key])
})
......@@ -45,7 +45,7 @@ const ModalEventDonorSubmission = ({ show, handleClose }) => {
window.alert("Pengajuan acara donor telah disimpan.")
handleClose()
})
.catch(error => {
.catch((error) => {
if (error.response) {
window.alert(JSON.stringify(error.response.data))
} else {
......
import { idGeneratorFactory } from "../utils/number"
const idGenerator = idGeneratorFactory(1)
export const artikelEdukasiFactory = override => ({
id: idGenerator(),
title: "Test Title",
featured_image: "http://localhost:8080/media/edukasi/placeholder1.jpg",
content:
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
...override,
})
import { Link } from "gatsby"
import React from "react"
import Slider from "react-animated-slider"
import { useQuery } from "react-query"
import { getListArtikelEdukasi } from "../api"
import ErrorRetry from "../components/error-retry"
import Spinner from "../components/spinner"
import "./slider.css"
export default () => {
const { status, data, refetch } = useQuery("artikel-edukasi", () =>
getListArtikelEdukasi(1)
)
return (
<>
{status === "loading" ? (
<Spinner />
) : status === "error" ? (
<ErrorRetry retry={refetch} />
) : (
<Slider classNames="slider">
{data.data.results.map((item, index) => (
<div
key={index}
style={{
background: `url('${item.featured_image}') no-repeat center center`,
}}
>
<Link to={"/article/" + item.id} className="unstyled-link">
<div className="center bg-red">
<p>{item.title}</p>
</div>
</Link>
</div>
))}
</Slider>
)}
</>
)
}
import { screen } from "@testing-library/react"
import React from "react"
import { getListArtikelEdukasi } from "../api"
import { render } from "../utils/test-util"
import { artikelEdukasiFactory } from "./artikel-edukasi.factory"
import Slider from "./carousel"
getListArtikelEdukasi.mockResolvedValue({ data: { results: [] } })
describe("Carousel", () => {
it("mounts", () => {
const slider = <Slider />
expect(slider).toBeDefined()
})
it("shows image title after load", async () => {
getListArtikelEdukasi.mockResolvedValueOnce({
data: {
results: [artikelEdukasiFactory({ title: "Test Title" })],
},
})
render(<Slider />)
expect(await screen.findByText("Test Title")).toBeInTheDocument()
})
})
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment