diff --git a/links/templates/links/api_docs.html b/links/templates/links/api_docs.html new file mode 100644 index 0000000..f8862cd --- /dev/null +++ b/links/templates/links/api_docs.html @@ -0,0 +1,24 @@ +{% extends 'base_blank.html' %} +{% load static %} +{% load i18n %} + +{% block title %}{% trans "API Documentation" %} - GoLinks{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} + + +{% endblock %} diff --git a/links/templates/links/help.html b/links/templates/links/help.html index 6aeb174..bb155a0 100644 --- a/links/templates/links/help.html +++ b/links/templates/links/help.html @@ -138,219 +138,7 @@ Custom pages allow you to create markdown-based web pages that can serve as docu **Example Use Cases:** Check http://go.junv.cc/custom/today/ -## API Usage -GoLinks provides RESTful APIs for programmatic access to pages. Here are the available endpoints and their usage: - -### List Pages - -Retrieve a paginated list of all pages: -``` -GET /api/pages/ -GET /api/pages/?page=2 -GET /api/pages/?page_size=20 -``` -Response examples: -``` -{ - "count": 100, - "next": "http://localhost:8000/api/pages/?page=2", - "previous": null, - "results": [ - { - "id": 1, - "url": "https://example.com", - "title": "Example Page", - "summary": "This is a summary", - "content": "This is the content", - "created_at": "2024-01-01T00:00:00Z", - "updated_at": "2024-01-01T00:00:00Z" - }, - // ... more pages - ] -} -``` -### Create a new Page - -``` -POST /api/pages/ -Content-Type: application/json - -{ - "url": "https://example.com", - "title": "Example Page", - "summary": "This is a summary", - "content": "This is the content" -} -``` -Response example: -``` -{ - "id": 1, - "url": "https://example.com", - "title": "Example Page", - "summary": "This is a summary", - "content": "This is the content", - "created_at": "2024-01-01T00:00:00Z", - "updated_at": "2024-01-01T00:00:00Z" -} -``` - -### List newsletters: - -``` -GET /api/newsletters/ -``` - -### Create a newsletter: -``` -curl -X POST http://localhost:8000/api/newsletters \ - -H "Content-Type: application/json" \ - -d '{ - "title": "Test Newsletter", - "type": "technology", - "content": "# Test Content\n\nThis is a test newsletter." - }' -``` - -## Collection API Usage - -GoLinks provides RESTful APIs for managing image collections. Here are the available endpoints and their usage: - -### List Collections - -Retrieve a paginated list of all collections: -``` -GET /api/collections -GET /api/collections?page=2 -GET /api/collections?page_size=20 -``` -Response example: -```json -{ - "count": 10, - "next": "http://localhost:8000/api/collections?page=2", - "previous": null, - "results": [ - { - "id": "550e8400-e29b-41d4-a716-446655440000", - "name": "My Collection", - "description": "A collection of images", - "image_count": 5, - "created_at": "2024-01-01T00:00:00Z" - }, - // ... more collections - ] -} -``` - -### Create a Collection - -Create a new image collection: -``` -POST /api/collections -Content-Type: application/json - -{ - "name": "My Collection", - "description": "A collection of images" -} -``` -Response example: -```json -{ - "status": "success", - "message": "Collection created successfully", - "data": { - "id": "550e8400-e29b-41d4-a716-446655440000", - "name": "My Collection", - "description": "A collection of images", - "image_count": 0, - "created_at": "2024-01-01T00:00:00Z" - } -} -``` - -### Upload Images to Collection - -Upload one or multiple images to a collection: -``` -POST /api/collections/{collection_id}/upload_images -Content-Type: multipart/form-data - -file: image1.jpg -file: image2.jpg -``` -Response example: -```json -{ - "status": "success", - "message": "Successfully uploaded 2 images", - "data": [ - { - "id": "550e8400-e29b-41d4-a716-446655440001", - "title": "image1.jpg", - "content_type": "image/jpeg", - "size": 1024000, - "url": "https://your-r2-domain.com/images/...", - "created_at": "2024-01-01T00:00:00Z" - }, - { - "id": "550e8400-e29b-41d4-a716-446655440002", - "title": "image2.jpg", - "content_type": "image/jpeg", - "size": 2048000, - "url": "https://your-r2-domain.com/images/...", - "created_at": "2024-01-01T00:00:00Z" - } - ] -} -``` - -### Delete an Image - -Delete a specific image from a collection: -``` -DELETE /api/images/{image_id} -``` -Response example: -```json -{ - "status": "success", - "message": "Image deleted successfully" -} -``` - -### Delete a Collection - -Delete a collection and all its images: -``` -DELETE /api/collections/{collection_id} -``` -Response example: -```json -{ - "status": "success", - "message": "Collection deleted successfully" -} -``` - -### Error Responses - -In case of errors, the API will return appropriate status codes and error messages: -```json -{ - "status": "error", - "message": "Error description here" -} -``` - -Common status codes: -- 200: Success -- 201: Created -- 400: Bad Request -- 404: Not Found -- 500: Internal Server Error {% endfilter %} diff --git a/links/urls.py b/links/urls.py index d9e3b22..5189a73 100644 --- a/links/urls.py +++ b/links/urls.py @@ -4,6 +4,7 @@ from . import page_views from . import search_views from . import newsletter_views from . import collection_views +from django.views.generic import TemplateView urlpatterns = [ # Regular UI URLs @@ -39,6 +40,15 @@ urlpatterns = [ path('ui/newsletters//edit/', newsletter_views.NewsletterUpdateView.as_view(), name='newsletter-update'), path('ui/newsletters//delete/', newsletter_views.NewsletterDeleteView.as_view(), name='newsletter-delete'), + # Collection slideshow + path('ui/collections//slideshow/', + collection_views.CollectionSlideshowView.as_view(), + name='collection-slideshow'), + + # API Documentation + path('ui/api-docs/', + TemplateView.as_view(template_name='links/api_docs.html'), + name='api-docs'), # Public newsletter URL path('public/newsletters//', newsletter_views.PublicNewsletterView.as_view(), @@ -52,8 +62,4 @@ urlpatterns = [ path('//', views.redirect_to_original, name='redirect_to_original_with_param'), path('alias//', views.LinkDetailView.as_view(), name='link_detail_by_alias'), - # Collection slideshow - path('ui/collections//slideshow/', - collection_views.CollectionSlideshowView.as_view(), - name='collection-slideshow'), ] diff --git a/new_theme/static/css/dist/styles.css b/new_theme/static/css/dist/styles.css index 71d1cf1..a75ee87 100644 --- a/new_theme/static/css/dist/styles.css +++ b/new_theme/static/css/dist/styles.css @@ -1388,6 +1388,11 @@ video { background-color: rgb(254 249 195 / var(--tw-bg-opacity)); } +.bg-gray-900 { + --tw-bg-opacity: 1; + background-color: rgb(17 24 39 / var(--tw-bg-opacity)); +} + .bg-opacity-50 { --tw-bg-opacity: 0.5; } @@ -1784,6 +1789,11 @@ video { color: rgb(133 77 14 / var(--tw-text-opacity)); } +.text-gray-300 { + --tw-text-opacity: 1; + color: rgb(209 213 219 / var(--tw-text-opacity)); +} + .underline { text-decoration-line: underline; } @@ -1998,6 +2008,11 @@ video { background-color: rgb(185 28 28 / var(--tw-bg-opacity)); } +.hover\:bg-gray-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); +} + .hover\:text-blue-200:hover { --tw-text-opacity: 1; color: rgb(191 219 254 / var(--tw-text-opacity)); @@ -2068,6 +2083,11 @@ video { color: rgb(153 27 27 / var(--tw-text-opacity)); } +.hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + .hover\:underline:hover { text-decoration-line: underline; } diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..571b3d4 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,404 @@ +openapi: 3.1.0 +info: + title: GoLinks API + description: API documentation for GoLinks service + version: 1.0.0 + +servers: + - url: http://localhost:8000 + description: Local development server + +paths: + /api/pages: + get: + summary: List all pages + description: Retrieve a paginated list of all pages + parameters: + - in: query + name: page + schema: + type: integer + description: Page number for pagination + - in: query + name: page_size + schema: + type: integer + description: Number of items per page + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/PageList' + + post: + summary: Create a new page + description: Create a new page with the provided data + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PageCreate' + responses: + '201': + description: Page created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + + /api/newsletters: + get: + summary: List all newsletters + description: Retrieve a paginated list of all newsletters + parameters: + - in: query + name: page + schema: + type: integer + description: Page number for pagination + - in: query + name: page_size + schema: + type: integer + description: Number of items per page + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/NewsletterList' + + post: + summary: Create a new newsletter + description: Create a new newsletter with the provided data + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NewsletterCreate' + responses: + '201': + description: Newsletter created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Newsletter' + + /api/collections: + get: + summary: List all collections + description: Retrieve a paginated list of all image collections + parameters: + - in: query + name: page + schema: + type: integer + description: Page number for pagination + - in: query + name: page_size + schema: + type: integer + description: Number of items per page + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/CollectionList' + + post: + summary: Create a new collection + description: Create a new image collection + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CollectionCreate' + responses: + '201': + description: Collection created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/CollectionResponse' + + /api/collections/{collection_id}: + delete: + summary: Delete a collection + description: Delete a collection and all its images + parameters: + - in: path + name: collection_id + required: true + schema: + type: string + format: uuid + description: The ID of the collection to delete + responses: + '200': + description: Collection deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + + /api/collections/{collection_id}/upload_images: + post: + summary: Upload images to collection + description: Upload one or multiple images to a collection + parameters: + - in: path + name: collection_id + required: true + schema: + type: string + format: uuid + description: The ID of the collection + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: array + items: + type: string + format: binary + responses: + '201': + description: Images uploaded successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ImageUploadResponse' + + /api/images/{image_id}: + delete: + summary: Delete an image + description: Delete a specific image from a collection + parameters: + - in: path + name: image_id + required: true + schema: + type: string + format: uuid + description: The ID of the image to delete + responses: + '200': + description: Image deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + +components: + schemas: + Page: + type: object + properties: + id: + type: integer + url: + type: string + title: + type: string + summary: + type: string + content: + type: string + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + PageCreate: + type: object + required: + - url + - title + properties: + url: + type: string + title: + type: string + summary: + type: string + content: + type: string + + PageList: + type: object + properties: + count: + type: integer + next: + type: string + nullable: true + previous: + type: string + nullable: true + results: + type: array + items: + $ref: '#/components/schemas/Page' + + Newsletter: + type: object + properties: + id: + type: integer + title: + type: string + type: + type: string + enum: [technology, world_news] + content: + type: string + created_at: + type: string + format: date-time + + NewsletterCreate: + type: object + required: + - title + - type + - content + properties: + title: + type: string + type: + type: string + enum: [technology, world_news] + content: + type: string + + NewsletterList: + type: object + properties: + count: + type: integer + next: + type: string + nullable: true + previous: + type: string + nullable: true + results: + type: array + items: + $ref: '#/components/schemas/Newsletter' + + Collection: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + description: + type: string + image_count: + type: integer + created_at: + type: string + format: date-time + + CollectionCreate: + type: object + required: + - name + properties: + name: + type: string + description: + type: string + + CollectionList: + type: object + properties: + count: + type: integer + next: + type: string + nullable: true + previous: + type: string + nullable: true + results: + type: array + items: + $ref: '#/components/schemas/Collection' + + CollectionResponse: + type: object + properties: + status: + type: string + enum: [success] + message: + type: string + data: + $ref: '#/components/schemas/Collection' + + Image: + type: object + properties: + id: + type: string + format: uuid + title: + type: string + content_type: + type: string + size: + type: integer + url: + type: string + created_at: + type: string + format: date-time + + ImageUploadResponse: + type: object + properties: + status: + type: string + enum: [success] + message: + type: string + data: + type: array + items: + $ref: '#/components/schemas/Image' + + SuccessResponse: + type: object + properties: + status: + type: string + enum: [success] + message: + type: string + + ErrorResponse: + type: object + properties: + status: + type: string + enum: [error] + message: + type: string diff --git a/static/openapi.yaml b/static/openapi.yaml new file mode 100644 index 0000000..571b3d4 --- /dev/null +++ b/static/openapi.yaml @@ -0,0 +1,404 @@ +openapi: 3.1.0 +info: + title: GoLinks API + description: API documentation for GoLinks service + version: 1.0.0 + +servers: + - url: http://localhost:8000 + description: Local development server + +paths: + /api/pages: + get: + summary: List all pages + description: Retrieve a paginated list of all pages + parameters: + - in: query + name: page + schema: + type: integer + description: Page number for pagination + - in: query + name: page_size + schema: + type: integer + description: Number of items per page + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/PageList' + + post: + summary: Create a new page + description: Create a new page with the provided data + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PageCreate' + responses: + '201': + description: Page created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Page' + + /api/newsletters: + get: + summary: List all newsletters + description: Retrieve a paginated list of all newsletters + parameters: + - in: query + name: page + schema: + type: integer + description: Page number for pagination + - in: query + name: page_size + schema: + type: integer + description: Number of items per page + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/NewsletterList' + + post: + summary: Create a new newsletter + description: Create a new newsletter with the provided data + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NewsletterCreate' + responses: + '201': + description: Newsletter created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/Newsletter' + + /api/collections: + get: + summary: List all collections + description: Retrieve a paginated list of all image collections + parameters: + - in: query + name: page + schema: + type: integer + description: Page number for pagination + - in: query + name: page_size + schema: + type: integer + description: Number of items per page + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/CollectionList' + + post: + summary: Create a new collection + description: Create a new image collection + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CollectionCreate' + responses: + '201': + description: Collection created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/CollectionResponse' + + /api/collections/{collection_id}: + delete: + summary: Delete a collection + description: Delete a collection and all its images + parameters: + - in: path + name: collection_id + required: true + schema: + type: string + format: uuid + description: The ID of the collection to delete + responses: + '200': + description: Collection deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + + /api/collections/{collection_id}/upload_images: + post: + summary: Upload images to collection + description: Upload one or multiple images to a collection + parameters: + - in: path + name: collection_id + required: true + schema: + type: string + format: uuid + description: The ID of the collection + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: array + items: + type: string + format: binary + responses: + '201': + description: Images uploaded successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ImageUploadResponse' + + /api/images/{image_id}: + delete: + summary: Delete an image + description: Delete a specific image from a collection + parameters: + - in: path + name: image_id + required: true + schema: + type: string + format: uuid + description: The ID of the image to delete + responses: + '200': + description: Image deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + +components: + schemas: + Page: + type: object + properties: + id: + type: integer + url: + type: string + title: + type: string + summary: + type: string + content: + type: string + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + + PageCreate: + type: object + required: + - url + - title + properties: + url: + type: string + title: + type: string + summary: + type: string + content: + type: string + + PageList: + type: object + properties: + count: + type: integer + next: + type: string + nullable: true + previous: + type: string + nullable: true + results: + type: array + items: + $ref: '#/components/schemas/Page' + + Newsletter: + type: object + properties: + id: + type: integer + title: + type: string + type: + type: string + enum: [technology, world_news] + content: + type: string + created_at: + type: string + format: date-time + + NewsletterCreate: + type: object + required: + - title + - type + - content + properties: + title: + type: string + type: + type: string + enum: [technology, world_news] + content: + type: string + + NewsletterList: + type: object + properties: + count: + type: integer + next: + type: string + nullable: true + previous: + type: string + nullable: true + results: + type: array + items: + $ref: '#/components/schemas/Newsletter' + + Collection: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + description: + type: string + image_count: + type: integer + created_at: + type: string + format: date-time + + CollectionCreate: + type: object + required: + - name + properties: + name: + type: string + description: + type: string + + CollectionList: + type: object + properties: + count: + type: integer + next: + type: string + nullable: true + previous: + type: string + nullable: true + results: + type: array + items: + $ref: '#/components/schemas/Collection' + + CollectionResponse: + type: object + properties: + status: + type: string + enum: [success] + message: + type: string + data: + $ref: '#/components/schemas/Collection' + + Image: + type: object + properties: + id: + type: string + format: uuid + title: + type: string + content_type: + type: string + size: + type: integer + url: + type: string + created_at: + type: string + format: date-time + + ImageUploadResponse: + type: object + properties: + status: + type: string + enum: [success] + message: + type: string + data: + type: array + items: + $ref: '#/components/schemas/Image' + + SuccessResponse: + type: object + properties: + status: + type: string + enum: [success] + message: + type: string + + ErrorResponse: + type: object + properties: + status: + type: string + enum: [error] + message: + type: string diff --git a/templates/base.html b/templates/base.html index 9a3a31e..8e95414 100644 --- a/templates/base.html +++ b/templates/base.html @@ -113,14 +113,6 @@ {% trans "Screenshots" %} - -
- - - - {% trans "Help" %} -
-
@@ -130,6 +122,24 @@ {% trans "Images" %}
+ +
+ + + + {% trans "APIs" %} +
+
+ + +
+ + + + {% trans "Help" %} +
+