diff --git a/alttextbackend/data/postgres/__init__.py b/alttextbackend/data/postgres/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/alttextbackend/data/postgres/books.py b/alttextbackend/data/postgres/books.py index c5ecbbf..b8afa0c 100644 --- a/alttextbackend/data/postgres/books.py +++ b/alttextbackend/data/postgres/books.py @@ -1,12 +1,17 @@ import uuid +import os +import django +import sys -try: - from .config import Database -except ImportError: - from config import Database +current_script_path = os.path.dirname(os.path.abspath(__file__)) +project_root = os.path.join(current_script_path, '..', '..', '..') +sys.path.insert(0, os.path.abspath(project_root)) -from django.db import connection +os.environ.setdefault('DJANGO_SETTINGS_MODULE', "alttextbackend.settings") +django.setup() + +from alttextbackend.data.postgres.models import Book """ @@ -19,14 +24,6 @@ BOOKS DATABASE ATTRIBUTES coverExt: str """ - -def createBookTable(): - query = "CREATE TABLE books (id varchar(255) NOT NULL PRIMARY KEY, title varchar(255), size varchar(255), status varchar(255), numImages int, coverExt varchar(255));" - with connection.cursor() as cursor: - cursor.execute(query) - return cursor.fetchall() - - def jsonifyBook(book: tuple): return { "id": book[0], @@ -39,37 +36,34 @@ def jsonifyBook(book: tuple): def getBook(id: str): - db = Database() - query = "SELECT * FROM books WHERE id = %s" - params = (id,) - db.sendQuery(query, params) - book = db.fetchOne() - db.close() - return book + book_tuple = Book.objects.filter(id=id).values_list( + 'id', 'title', 'size', 'status', 'numImages', 'coverExt', named=False + ).first() + + # Check if a book was found; if not, return None + if book_tuple is None: + return None + + return book_tuple def getBooks(titleQ: str = None, limit: int = None, skip: int = None): - db = Database() - params = [] - query = "SELECT * FROM books" - + books_query = Book.objects.all() + + # Filter by title if a title query is provided if titleQ: - lowerTitleQ = f"%{titleQ.lower()}%" - query += " WHERE LOWER(title) LIKE %s" - params.append(lowerTitleQ) - - if limit is not None: - query += " LIMIT %s" - params.append(limit) - + books_query = books_query.filter(title__icontains=titleQ) + + # Apply limit and skip (offset) if provided if skip is not None: - query += " OFFSET %s" - params.append(skip) - - db.sendQuery(query, params) - books = db.fetchAll() - db.close() - return books + books_query = books_query[skip:] # Skip the first `skip` records + if limit is not None: + books_query = books_query[:limit] # Take `limit` records from the query set + + # Execute the query and fetch the results + books = books_query.values_list('id', 'title', 'size', 'status', 'numImages', 'coverExt', flat=False) + + return list(books) def addBook( @@ -83,48 +77,30 @@ def addBook( if id == None: id = str(uuid.uuid4()) - db = Database() - query = "INSERT INTO books (id, title, status, numimages, size, coverext) VALUES (%s, %s, %s, %s, %s, %s);" - params = (id, title, status, numImages, size, coverExt) - db.sendQuery(query, params) - db.commit() - db.close() + newBook = Book( + id=id, + title=title, + size=size, + numImages=numImages, + status=status, + coverExt=coverExt + ) + newBook.save() return getBook(id) def deleteBook(id: str): - db = Database() - query = "DELETE FROM books WHERE id = %s" - params = (id,) - db.sendQuery(query, params) - db.commit() - db.close() - + myBook = Book.objects.get(id=id) + myBook.delete() def updateBook(id: str, title: str = None, status: str = None, coverExt: str = None): - db = Database() + update_fields = {} + if title is not None: + update_fields['title'] = title + if status is not None: + update_fields['status'] = status + if coverExt is not None: + update_fields['coverExt'] = coverExt - if title or status or coverExt: - params = [] - query = "UPDATE books SET" - - if title: - query += " title = %s," - params.append(title) - - if status: - query += " status = %s," - params.append(status) - - if coverExt: - query += " coverext = %s," - params.append(coverExt) - - query = query[:-1] - - query += " WHERE id = %s" - params.append(id) - db.sendQuery(query, params) - db.commit() - - db.close() + if update_fields: + Book.objects.filter(id=id).update(**update_fields) diff --git a/alttextbackend/data/postgres/images.py b/alttextbackend/data/postgres/images.py index b76ca7c..734dcb3 100644 --- a/alttextbackend/data/postgres/images.py +++ b/alttextbackend/data/postgres/images.py @@ -1,7 +1,17 @@ -try: - from .config import Database -except ImportError: - from config import Database +import sys +import os +import django + + +current_script_path = os.path.dirname(os.path.abspath(__file__)) +project_root = os.path.join(current_script_path, '..', '..', '..') +sys.path.insert(0, os.path.abspath(project_root)) + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', "alttextbackend.settings") +django.setup() + +from alttextbackend.data.postgres.models import Image, Book + """ IMAGE DATABASE ATTRIBUTES @@ -19,15 +29,6 @@ IMAGE DATABASE ATTRIBUTES additionalContext: str """ - -def createImageTable(): - db = Database() - query = "CREATE TABLE images (bookid varchar(255) NOT NULL, src varchar(255) NOT NULL, hash varchar(255), status varchar(255), alt varchar(1000), originalAlt varchar(1000), genAlt varchar(1000), genImageCaption varchar(1000), ocr varchar(1000), beforeContext varchar(2000), afterContext varchar(2000), additionalContext varchar(1000), CONSTRAINT PK_Image PRIMARY KEY (bookid, src), FOREIGN KEY (bookid) REFERENCES books(id) ON DELETE CASCADE);" - db.sendQuery(query) - db.commit() - db.close() - - def jsonifyImage(image: tuple): return { "bookid": image[0], @@ -46,33 +47,39 @@ def jsonifyImage(image: tuple): def getImageByBook(bookid: str, src: str): - db = Database() - query = "SELECT * FROM images WHERE bookid = %s AND src = %s" - params = (bookid, src) - db.sendQuery(query, params) - image = db.fetchOne() - db.close - return image + book = Book.objects.get(id=bookid) + image_tuple = Image.objects.filter(book=book, src=src).values_list( + 'book_id', 'src', 'hash', 'status', 'alt', 'originalAlt', + 'genAlt', 'genImageCaption', 'ocr', 'beforeContext', + 'afterContext', 'additionalContext', named=False + ).first() + + # Check if an image was found; if not, return None + if image_tuple is None: + return None + + return image_tuple def getImagesByBook(bookid: str): - db = Database() - query = "SELECT * FROM images WHERE bookid = %s" - params = (bookid,) - db.sendQuery(query, params) - images = db.fetchAll() - db.close() - return images + book = Book.objects.get(id=bookid) + images_tuples = Image.objects.filter(book=book).values_list( + 'book_id', 'src', 'hash', 'status', 'alt', 'originalAlt', + 'genAlt', 'genImageCaption', 'ocr', 'beforeContext', + 'afterContext', 'additionalContext', named=False + ) + + return list(images_tuples) def getImagesByHash(hash: str): - db = Database() - query = "SELECT * FROM images WHERE hash = %s" - params = (hash,) - db.sendQuery(query, params) - images = db.fetchAll() - db.close() - return images + images_tuples = Image.objects.filter(hash=hash).values_list( + 'book_id', 'src', 'hash', 'status', 'alt', 'originalAlt', + 'genAlt', 'genImageCaption', 'ocr', 'beforeContext', + 'afterContext', 'additionalContext', named=False + ) + + return list(images_tuples) def addImage( @@ -89,53 +96,42 @@ def addImage( afterContext: str = None, additionalContext: str = None, ): - db = Database() - query = "INSERT INTO images (bookid, src, hash, status, alt, originalalt, genalt, genimagecaption, ocr, beforecontext, aftercontext, additionalcontext) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" - if status != "available" and status != "processing": - status = "available" - if alt is not None: - alt = alt[:1000] - if originalAlt is not None: - originalAlt = originalAlt[:1000] - if genAlt is not None: - genAlt = genAlt[:1000] - if genImageCaption is not None: - genImageCaption = genImageCaption[:1000] - if ocr is not None: - ocr = ocr[:1000] - if beforeContext is not None: - beforeContext = beforeContext[:2000] - if afterContext is not None: - afterContext = afterContext[:2000] - if additionalContext is not None: - additionalContext = additionalContext[:1000] - params = ( - bookid, - src, - hash, - status, - alt, - originalAlt, - genAlt, - genImageCaption, - ocr, - beforeContext, - afterContext, - additionalContext, + status = status if status in ["available", "processing"] else "available" + + # Truncate strings to their maximum allowed length based on the model's definitions + alt = alt[:1000] if alt is not None else None + originalAlt = originalAlt[:1000] if originalAlt is not None else None + genAlt = genAlt[:1000] if genAlt is not None else None + genImageCaption = genImageCaption[:1000] if genImageCaption is not None else None + ocr = ocr[:1000] if ocr is not None else None + beforeContext = beforeContext[:2000] if beforeContext is not None else None + afterContext = afterContext[:2000] if afterContext is not None else None + additionalContext = additionalContext[:1000] if additionalContext is not None else None + + book_instance = Book.objects.get(id=bookid) + + # Create and save the new Image instance + new_image = Image.objects.create( + book=book_instance, + src=src, + hash=hash, + status=status, + alt=alt, + originalAlt=originalAlt, + genAlt=genAlt, + genImageCaption=genImageCaption, + ocr=ocr, + beforeContext=beforeContext, + afterContext=afterContext, + additionalContext=additionalContext, ) - db.sendQuery(query, params) - db.commit() - db.close() - return getImageByBook(bookid, src) + + return new_image def deleteImage(bookid: str, src: str): - db = Database() - query = "DELETE FROM images WHERE bookid = %s AND src = %s;" - params = (bookid, src) - db.sendQuery(query, params) - db.commit() - db.close() + book = Book.objects.get(id=bookid) + Image.objects.filter(book=book, src=src).delete() def updateImage( @@ -150,59 +146,25 @@ def updateImage( afterContext: str = None, additionalContext: str = None, ): - db = Database() + update_fields = {} + if status is not None: + update_fields['status'] = status + if alt is not None: + update_fields['alt'] = alt + if genAlt is not None: + update_fields['genAlt'] = genAlt + if genImageCaption is not None: + update_fields['genImageCaption'] = genImageCaption + if ocr is not None: + update_fields['ocr'] = ocr + if beforeContext is not None: + update_fields['beforeContext'] = beforeContext + if afterContext is not None: + update_fields['afterContext'] = afterContext + if additionalContext is not None: + update_fields['additionalContext'] = additionalContext - if ( - status - or alt - or genAlt - or genImageCaption - or ocr - or beforeContext - or afterContext - or additionalContext - ): - params = [] - query = "UPDATE images SET" - - if status: - query += " status = %s," - params.append(status) - - if alt: - query += " alt = %s," - params.append(alt) - - if genAlt: - query += " genalt = %s," - params.append(genAlt) - - if genImageCaption: - query += " genimagecaption = %s," - params.append(genImageCaption) - - if ocr: - query += " ocr = %s," - params.append(ocr) - - if beforeContext: - query += " beforecontext = %s," - params.append(beforeContext) - - if afterContext: - query += " aftercontext = %s," - params.append(afterContext) - - if additionalContext: - query += " additionalcontext = %s," - params.append(additionalContext) - - query = query[:-1] - - query += " WHERE bookid = %s AND src = %s" - params.append(bookid) - params.append(src) - db.sendQuery(query, params) - db.commit() - - db.close() + # Only execute the update if there are fields to update + if update_fields: + book = Book.objects.get(id=bookid) + Image.objects.filter(book=book, src=src).update(**update_fields) diff --git a/alttextbackend/data/postgres/migrations/0001_initial.py b/alttextbackend/data/postgres/migrations/0001_initial.py new file mode 100644 index 0000000..59fa92b --- /dev/null +++ b/alttextbackend/data/postgres/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0.3 on 2024-03-26 23:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Book', + fields=[ + ('id', models.CharField(max_length=255, primary_key=True, serialize=False)), + ('title', models.CharField(blank=True, max_length=255, null=True)), + ('size', models.CharField(blank=True, max_length=255, null=True)), + ('status', models.CharField(blank=True, max_length=255, null=True)), + ('num_images', models.IntegerField(blank=True, null=True)), + ('cover_ext', models.CharField(blank=True, max_length=255, null=True)), + ], + ), + ] diff --git a/alttextbackend/data/postgres/migrations/0002_image.py b/alttextbackend/data/postgres/migrations/0002_image.py new file mode 100644 index 0000000..7cf7a1f --- /dev/null +++ b/alttextbackend/data/postgres/migrations/0002_image.py @@ -0,0 +1,35 @@ +# Generated by Django 5.0.3 on 2024-03-27 20:32 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('postgres', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Image', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('src', models.CharField(max_length=255)), + ('hash', models.CharField(blank=True, max_length=255, null=True)), + ('status', models.CharField(blank=True, max_length=255, null=True)), + ('alt', models.TextField(blank=True, null=True)), + ('original_alt', models.TextField(blank=True, null=True)), + ('gen_alt', models.TextField(blank=True, null=True)), + ('gen_image_caption', models.TextField(blank=True, null=True)), + ('ocr', models.TextField(blank=True, null=True)), + ('before_context', models.TextField(blank=True, null=True)), + ('after_context', models.TextField(blank=True, null=True)), + ('additional_context', models.TextField(blank=True, null=True)), + ('book', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='postgres.book')), + ], + options={ + 'unique_together': {('book', 'src')}, + }, + ), + ] diff --git a/alttextbackend/data/postgres/migrations/0003_alter_book_table_alter_image_table.py b/alttextbackend/data/postgres/migrations/0003_alter_book_table_alter_image_table.py new file mode 100644 index 0000000..95ee2f4 --- /dev/null +++ b/alttextbackend/data/postgres/migrations/0003_alter_book_table_alter_image_table.py @@ -0,0 +1,21 @@ +# Generated by Django 5.0.3 on 2024-03-27 20:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('postgres', '0002_image'), + ] + + operations = [ + migrations.AlterModelTable( + name='book', + table='book', + ), + migrations.AlterModelTable( + name='image', + table='image', + ), + ] diff --git a/alttextbackend/data/postgres/migrations/0004_rename_cover_ext_book_coverext_and_more.py b/alttextbackend/data/postgres/migrations/0004_rename_cover_ext_book_coverext_and_more.py new file mode 100644 index 0000000..0572f59 --- /dev/null +++ b/alttextbackend/data/postgres/migrations/0004_rename_cover_ext_book_coverext_and_more.py @@ -0,0 +1,53 @@ +# Generated by Django 5.0.3 on 2024-03-27 23:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('postgres', '0003_alter_book_table_alter_image_table'), + ] + + operations = [ + migrations.RenameField( + model_name='book', + old_name='cover_ext', + new_name='coverExt', + ), + migrations.RenameField( + model_name='book', + old_name='num_images', + new_name='numImages', + ), + migrations.RenameField( + model_name='image', + old_name='additional_context', + new_name='additionalContext', + ), + migrations.RenameField( + model_name='image', + old_name='after_context', + new_name='afterContext', + ), + migrations.RenameField( + model_name='image', + old_name='before_context', + new_name='beforeContext', + ), + migrations.RenameField( + model_name='image', + old_name='gen_alt', + new_name='genAlt', + ), + migrations.RenameField( + model_name='image', + old_name='gen_image_caption', + new_name='genImageCaption', + ), + migrations.RenameField( + model_name='image', + old_name='original_alt', + new_name='originalAlt', + ), + ] diff --git a/alttextbackend/data/postgres/migrations/0005_alter_book_table_alter_image_table.py b/alttextbackend/data/postgres/migrations/0005_alter_book_table_alter_image_table.py new file mode 100644 index 0000000..d60512b --- /dev/null +++ b/alttextbackend/data/postgres/migrations/0005_alter_book_table_alter_image_table.py @@ -0,0 +1,21 @@ +# Generated by Django 5.0.3 on 2024-03-27 23:05 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('postgres', '0004_rename_cover_ext_book_coverext_and_more'), + ] + + operations = [ + migrations.AlterModelTable( + name='book', + table='books', + ), + migrations.AlterModelTable( + name='image', + table='images', + ), + ] diff --git a/alttextbackend/data/postgres/migrations/__init__.py b/alttextbackend/data/postgres/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/alttextbackend/data/postgres/models.py b/alttextbackend/data/postgres/models.py new file mode 100644 index 0000000..87f168c --- /dev/null +++ b/alttextbackend/data/postgres/models.py @@ -0,0 +1,36 @@ +from django.db import models + +class Book(models.Model): + id = models.CharField(max_length=255, primary_key=True) + title = models.CharField(max_length=255, blank=True, null=True) + size = models.CharField(max_length=255, blank=True, null=True) + status = models.CharField(max_length=255, blank=True, null=True) + numImages = models.IntegerField(null=True, blank=True) + coverExt = models.CharField(max_length=255, blank=True, null=True) + + class Meta: + db_table = 'books' + + def __str__(self): + return self.title + +class Image(models.Model): + book = models.ForeignKey('Book', on_delete=models.CASCADE) + src = models.CharField(max_length=255) + hash = models.CharField(max_length=255, blank=True, null=True) + status = models.CharField(max_length=255, blank=True, null=True) + alt = models.TextField(blank=True, null=True) + originalAlt = models.TextField(blank=True, null=True) + genAlt = models.TextField(blank=True, null=True) + genImageCaption = models.TextField(blank=True, null=True) + ocr = models.TextField(blank=True, null=True) + beforeContext = models.TextField(blank=True, null=True) + afterContext = models.TextField(blank=True, null=True) + additionalContext = models.TextField(blank=True, null=True) + + class Meta: + db_table = 'images' + unique_together = ('book', 'src') + + def __str__(self): + return f"Image {self.src} of Book {self.book.id}" \ No newline at end of file diff --git a/alttextbackend/data/postgres/test.py b/alttextbackend/data/postgres/test.py index 8ce8815..510146a 100644 --- a/alttextbackend/data/postgres/test.py +++ b/alttextbackend/data/postgres/test.py @@ -1,16 +1,31 @@ import dotenv -from books import addBook, getBooks, getBook, updateBook +from books import addBook, getBooks, getBook, updateBook, deleteBook from images import ( addImage, getImagesByBook, getImageByBook, getImagesByHash, updateImage, + deleteImage, ) from config import Database +import os +import django +import sys dotenv.load_dotenv() + +#project_root = "/SeniorD/alt-text-backend" +#sys.path.insert(0, project_root) + +# Set the Django settings module +#os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'alttextbackend.settings') + +# Prepare the Django project for use +#django.setup() + + """ createBookTable = "CREATE TABLE books (id varchar(255) NOT NULL PRIMARY KEY, title varchar(255), size varchar(255), status varchar(255), numImages int, coverExt varchar(255));" createImageTable = "CREATE TABLE images (bookid varchar(255) NOT NULL, src varchar(255) NOT NULL, hash varchar(255), status varchar(255), alt varchar(255), originalAlt varchar(255), genAlt varchar(255), genImageCaption varchar(255), ocr varchar(255), beforeContext varchar(255), afterContext varchar(255), additionalContext varchar(255), CONSTRAINT PK_Image PRIMARY KEY (bookid, src), FOREIGN KEY (bookid) REFERENCES books(id) ON DELETE CASCADE);" @@ -19,37 +34,47 @@ createImageTable = "CREATE TABLE images (bookid varchar(255) NOT NULL, src varch # db.sendQuery("SELECT * FROM books") # print(db.fetchOne()) -# addBook(title="Harry Potter", size="300kb", numImages=25) +#addBook(title="Harry Potter", size="300kb", numImages=25) """ addBook(title="Harry Potter", size="300kb", numImages=25) addBook(title="Harraoeu", size="300kb", numImages=25) addBook(title="Hartter", size="300kb", numImages=25) """ -# getBooks(titleQ="Harry Potter", limit=1, skip=2) +#print(getBooks()) + +#deleteBook('43198a6e-73ad-4e57-a2df-a7c9c7f8ce9a') """ addImage( - bookid="f1ac43cc-9f6d-4dc8-ac4f-aea0c4af5198", - src="sampleSrcMEOW", + bookid="845e7e66-860c-4df1-b64e-82c805c5cc3c", + src="sampleSrcMEOW2222", hash="brown", status="available", + genAlt="yeahhhh" ) """ -# getImagesByBook("fa47d830-586a-485f-a579-67b33fd3eae3") +print(getImageByBook(bookid="845e7e66-860c-4df1-b64e-82c805c5cc3c", src="sampleSrcMEOW")) -# print(getImagesByHash("brown")) +#print(getBook("845e7e66-860c-4df1-b64e-82c805c5cc3c")) +#print(getImagesByBook("845e7e66-860c-4df1-b64e-82c805c5cc3c")) + +#print(getImagesByHash("brown")) +""" updateImage( - bookid="f1ac43cc-9f6d-4dc8-ac4f-aea0c4af5198", + bookid="845e7e66-860c-4df1-b64e-82c805c5cc3c", src="sampleSrcMEOW", - status="bruh2", + status="bruh2234234", beforeContext="before context be like", ) +""" +#deleteImage(bookid="845e7e66-860c-4df1-b64e-82c805c5cc3c", src="sampleSrcMEOW2222") -# updateBook(id="72950", title="Test Title Two", status="available") +#updateBook(id="845e7e66-860c-4df1-b64e-82c805c5cc3c", coverExt="your mother") +#print(getBooks()) db = Database() # db.sendQuery("SELECT * FROM images;") diff --git a/alttextbackend/settings.py b/alttextbackend/settings.py index 4171736..c724837 100644 --- a/alttextbackend/settings.py +++ b/alttextbackend/settings.py @@ -11,6 +11,8 @@ https://docs.djangoproject.com/en/4.2/ref/settings/ """ from pathlib import Path +from dotenv import load_dotenv +load_dotenv() import os @@ -39,6 +41,7 @@ INSTALLED_APPS = [ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "alttextbackend.data.postgres", "rest_framework", ]