diff --git a/goodtimes/services.py b/goodtimes/services.py index e2faeb2..6488f7e 100644 --- a/goodtimes/services.py +++ b/goodtimes/services.py @@ -1,5 +1,7 @@ import random +import requests import googlemaps +import tweepy from django.conf import settings from django.core.files.uploadedfile import UploadedFile from django.core.mail import EmailMessage @@ -745,7 +747,7 @@ class GoogleMapsservice: def get_place_id_from_coordinates(self, latitude, longitude): """ Get the place ID of the given coordinates. - + :param latitude: Latitude of the location :param longitude: Longitude of the location :return: Place ID @@ -804,16 +806,287 @@ class GoogleMapsservice: if element["status"] == "OK" and element["distance"]["value"] <= radius_km * 1000 # Convert km to meters } + print(f"distance is {distances} and distances key is {distances.keys()}") + # Filter the queryset to include only events within the specified radius queryset = queryset.filter(id__in=distances.keys()) - # # Sort the event IDs by their distances in ascending order - # event_ids_by_distance = sorted(distances, key=distances.get) + print(f"query set after distance filter {queryset}") - # # Create a Case/When expression to preserve the order of events by distance - # preserved_order = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(event_ids_by_distance)]) - # print(f"preserved_order is {preserved_order}") - # # Order the queryset based on the preserved order - # queryset = queryset.order_by(preserved_order) + # Sort the event IDs by their distances in ascending order + event_ids_by_distance = sorted(distances, key=distances.get) + print(f"sort event by it distance {event_ids_by_distance}") + + # Create a Case/When expression to preserve the order of events by distance + preserved_order = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(event_ids_by_distance)]) + print(f"preserved_order is {preserved_order}") + # Order the queryset based on the preserved order + queryset = queryset.order_by(preserved_order) + for data in queryset: + print(f"queryset after preserverd order {data.id}") return queryset + + +class TwitterAPI: + def __init__(self): + self.api_key = settings.TWITTER_API_KEY + self.api_secret_key = settings.TWITTER_API_SECRET_KEY + self.access_token = settings.TWITTER_ACCESS_TOKEN + self.access_token_secret = settings.TWITTER_ACCESS_TOKEN_SECRET + self.client, self.api = self._setup_api() + + def _setup_api(self): + client = tweepy.Client( + consumer_key=self.api_key, + consumer_secret=self.api_secret_key, + access_token=self.access_token, + access_token_secret=self.access_token_secret, + ) + auth = tweepy.OAuth1UserHandler( + self.api_key, + self.api_secret_key, + self.access_token, + self.access_token_secret, + ) + api = tweepy.API(auth, wait_on_rate_limit=True) + return client, api + + def post_text_tweet(self, caption): + tweet = self.client.create_tweet(text=caption) + return tweet + + def post_image_with_caption(self, image_url, caption): + media = self.api.media_upload(image_url) + tweet = self.client.create_tweet(text=caption, media_ids=[media.media_id]) + return tweet + + +class TwitterPoster: + def __init__(self, twitter_api): + self.twitter_api = twitter_api + + def post_text_tweet(self, caption): + try: + tweet = self.twitter_api.post_text_tweet(caption) + return {'success': True, 'message': 'Tweet posted successfully!'} + except tweepy.TweepyException as e: + return {'success': False, 'message': f'Error posting tweet: {e}'} + + def post_image_with_caption(self, image_url, caption): + try: + tweet = self.twitter_api.post_image_with_caption(image_url, caption) + return {'success': True, 'message': 'Tweet posted successfully!'} + except tweepy.TweepyException as e: + return {'success': False, 'message': f'Error posting tweet: {e}'} + +class FacebookAPI: + def __init__(self): + self.app_id = settings.FACEBOOK_APP_ID + self.app_secret = settings.FACEBOOK_APP_SECRET + self.page_id = settings.FACEBOOK_PAGE_ID + self.page_access_token = None + + def _get_short_lived_user_access_token(self): + try: + url = f"https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id={self.app_id}&client_secret={self.app_secret}" + response = requests.get(url) + # response.raise_for_status() + print(f"short lived token {response.json()}") + return response.json()['access_token'] + except requests.exceptions.RequestException as e: + print(f"Error getting short-lived user access token: {e}") + return None + + def _get_long_lived_user_access_token(self, short_lived_token): + try: + url = f"https://graph.facebook.com/v20.0/oauth/access_token?grant_type=fb_exchange_token&client_id={self.app_id}&client_secret={self.app_secret}&fb_exchange_token={short_lived_token}" + response = requests.get(url) + # response.raise_for_status() + print(f"long lived access token : {response.json()}") + return response.json()['access_token'] + except requests.exceptions.RequestException as e: + print(f"Error getting long-lived user access token: {e}") + return None + + def _get_page_access_token(self, long_lived_token): + url = f"https://graph.facebook.com/{self.page_id}?fields=access_token&access_token={long_lived_token}" + response = requests.get(url) + # response.raise_for_status() + print(f"page access token is {response.json()}") + # self.page_access_token = response.json()["access_token"] + + def authenticate(self): + # short_lived_token = self._get_short_lived_user_access_token() + # if not short_lived_token: + # return False + # long_lived_token = self._get_long_lived_user_access_token(short_lived_token) + # if not long_lived_token: + # return False + # self._get_page_access_token(short_lived_token) + self.page_access_token = settings.FACEBOOK_ACCESS_TOKEN + return True + + def post_photo(self, image_url, caption): + if not self.page_access_token: + print("Page access token not obtained. Call authenticate() first.") + return False + try: + url = f"https://graph.facebook.com/v20.0/{self.page_id}/photos" + params = { + "message": caption, + "url": image_url, + "access_token": self.page_access_token, + } + response = requests.post(url, params=params) + # response.raise_for_status() + result = response.json() + if "id" not in result: + print(f"Error posting photo: {result}") + return False + print(f"Data posted successfully. Post Id: {result['id']}") + return True + except Exception as e: + print(f"Error posting photo: {e}") + return False + +class FacebookPoster: + def __init__(self, facebook_api): + self.facebook_api = facebook_api + + def post_photo(self, image_url, caption): + if not self.facebook_api.authenticate(): + print("Authentication failed. Please try again.") + return {'success': False, 'message': 'Error posting photo. Authenticate failed'} + result = self.facebook_api.post_photo(image_url, caption) + if not result: + return {'success': False, 'message': 'Error posting photo in Facebook'} + return {'success': True, 'message': 'Photo posted successfully'} + + + +# import requests + +# app_id = "YOUR_APP_ID" +# app_secret = "YOUR_APP_SECRET" +# page_id = "YOUR_PAGE_ID" # You need to specify the page ID +# # Step 1: Get an App Access Token +# response = requests.get(f"https://graph.facebook.com/oauth/access_token?client_id={app_id}&client_secret={app_secret}&grant_type=client_credentials") +# app_access_token = response.json()["access_token"] + +# # Step 2: Get a Page Access Token +# response = requests.get(f"https://graph.facebook.com/{page_id}?fields=access_token&access_token={app_access_token}") +# page_access_token = response.json()["access_token"] + +# # Use the Page Access Token to query the Page node +# response = requests.get(f"https://graph.facebook.com/{page_id}?access_token={page_access_token}") +# page_data = response.json() +# print(page_data) +class InstagramAPI: + def __init__(self): + self.app_id = settings.FACEBOOK_APP_ID + self.app_secret = settings.FACEBOOK_APP_SECRET + self.page_id = settings.INSTAGRAM_PAGE_ID + self.page_access_token = None + + def _get_short_lived_user_access_token(self): + try: + url = f"https://graph.facebook.com/oauth/access_token" + params = { + "grant_type": "client_credentials", + "client_id": self.app_id, + "client_secret": self.app_secret + } + response = requests.get(url, params=params) + response.raise_for_status() + print(f"Short-lived token: {response.json()}") + return response.json()['access_token'] + except requests.exceptions.RequestException as e: + print(f"Error getting short-lived user access token: {e}") + return None + + def _get_long_lived_user_access_token(self, short_lived_token): + try: + url = f"https://graph.facebook.com/v20.0/oauth/access_token" + params = { + "grant_type": "fb_exchange_token", + "client_id": self.app_id, + "client_secret": self.app_secret, + "fb_exchange_token": short_lived_token + } + response = requests.get(url, params=params) + response.raise_for_status() + print(f"Long-lived access token: {response.json()}") + return response.json()['access_token'] + except requests.exceptions.RequestException as e: + print(f"Error getting long-lived user access token: {e}") + return None + + def _get_page_access_token(self, long_lived_token): + try: + url = f"https://graph.facebook.com/{self.page_id}" + params = { + "fields": "access_token", + "access_token": long_lived_token + } + response = requests.get(url, params=params) + response.raise_for_status() + print(f"Page access token: {response.json()}") + return response.json()["access_token"] + except Exception as e: + print(f"Error getting page access token: {e}") + return None + + def authenticate(self): + # short_lived_token = self._get_short_lived_user_access_token() + # if not short_lived_token: + # return False + # long_lived_token = self._get_long_lived_user_access_token(short_lived_token) + # if not long_lived_token: + # return False + # self.page_access_token = self._get_page_access_token(long_lived_token) + self.page_access_token = settings.FACEBOOK_ACCESS_TOKEN + return True + + def post_image_with_caption(self, image_path, caption): + if not self.page_access_token: + print("Page access token not obtained. Call Authenticate() first.") + return False + try: + url = f"https://graph.facebook.com/v20.0/{self.page_id}/media" + params = { + "caption": caption, + "image_url": image_path, + "access_token": self.page_access_token + } + response = requests.post(url, data=params) + # response.raise_for_status() + result = response.json() + print(f"Post image with caption result: {result}") + + url = f"https://graph.facebook.com/v20.0/{self.page_id}/media_publish" + params = { + "creation_id": result["id"], + "access_token": self.page_access_token + } + response = requests.post(url, params=params) + # response.raise_for_status() + result = response.json() + return True + except Exception as e: + print(f"Error posting photo on instagram: {e}") + return False + + +class InstagramPoster: + def __init__(self, instagram_api): + self.instagram_api = instagram_api + + def post_image_with_caption(self, image_path, caption): + if not self.instagram_api.authenticate(): + print("Instagram API authentication failed.") + return {'success': False, 'message': 'Error posting photo. Authenticate failed'} + result = self.instagram_api.post_image_with_caption(image_path, caption) + if not result: + return {'success': False, 'message': 'Error posting photo in Instagram.'} + return {'success': True, 'message': 'Photo posted successfully'} \ No newline at end of file diff --git a/goodtimes/settings/base.py b/goodtimes/settings/base.py index 4009cbc..c4a02c3 100644 --- a/goodtimes/settings/base.py +++ b/goodtimes/settings/base.py @@ -343,3 +343,18 @@ PLACES_MAPS_API_KEY = env.str("GOOGLE_MAPS_API_KEY") PLACES_MAP_WIDGET_HEIGHT = 480 PLACES_MAP_OPTIONS = '{"center": { "lat": 38.971584, "lng": -95.235072 }, "zoom": 10}' PLACES_MARKER_OPTIONS = '{"draggable": true}' + +# twitter keys +TWITTER_API_KEY = env.str("TWITTER_API_KEY") +TWITTER_API_SECRET_KEY = env.str("TWITTER_API_SECRET_KEY") +TWITTER_ACCESS_TOKEN = env.str("TWITTER_ACCESS_TOKEN") +TWITTER_ACCESS_TOKEN_SECRET = env.str("TWITTER_ACCESS_TOKEN_SECRET") + +# facebook keys +FACEBOOK_APP_ID = env.str("FACEBOOK_APP_ID") +FACEBOOK_APP_SECRET = env.str("FACEBOOK_APP_SECRET") +FACEBOOK_PAGE_ID = env.str("FACEBOOK_PAGE_ID") +FACEBOOK_ACCESS_TOKEN = env.str("FACEBOOK_ACCESS_TOKEN") + +# Instagram Key +INSTAGRAM_PAGE_ID = env.str('INSTAGRAM_PAGE_ID') diff --git a/goodtimes/utils.py b/goodtimes/utils.py index 9fd4742..d85f258 100644 --- a/goodtimes/utils.py +++ b/goodtimes/utils.py @@ -59,8 +59,6 @@ class JsonResponseUtil: response_data["errors"] = errors return JsonResponse(response_data, status=status) - - class RandomGenerator: @staticmethod def number(start, end): diff --git a/manage_events/api/filters.py b/manage_events/api/filters.py index 08e7543..cb88f8c 100644 --- a/manage_events/api/filters.py +++ b/manage_events/api/filters.py @@ -31,4 +31,10 @@ class EventFilter(filters.FilterSet): def filter_category(self, queryset, name, value): category = value.split(',') - return queryset.filter(category__title__in=category) \ No newline at end of file + return queryset.filter(category__title__in=category) + + # def filter_queryset(self, queryset): + # queryset = super().filter_queryset(queryset) + # if 'price_from' in self.data or 'price_to' in self.data: + # queryset = queryset.order_by('entry_fee') + # return queryset \ No newline at end of file diff --git a/manage_events/api/serializers.py b/manage_events/api/serializers.py index 4529224..30982b0 100644 --- a/manage_events/api/serializers.py +++ b/manage_events/api/serializers.py @@ -50,6 +50,18 @@ class EventCategorySerializer(serializers.ModelSerializer): model = EventCategory fields = ["id", "title", "image", "description", "video_url"] + def get_image_url(self, obj, field_name, request): + image_field = getattr(obj, field_name) + if image_field: + return request.build_absolute_uri(image_field.url) + return "" + + def to_representation(self, instance): + data = super().to_representation(instance) + request = self.context.get("request") + data["image"] = self.get_image_url(instance, "image", request) + return data + class AgeGroupsSerializer(serializers.ModelSerializer): class Meta: model = AgeGroups diff --git a/manage_events/api/views.py b/manage_events/api/views.py index 860c65f..5bfd641 100644 --- a/manage_events/api/views.py +++ b/manage_events/api/views.py @@ -586,7 +586,7 @@ class EventPreferencesView(APIView): def get(self, request, *args, **kwargs): """Get all event categories for the authenticated user.""" obj = self.model.objects.filter(active=True, deleted=False) - serializer = self.serializer_class(obj, many=True) + serializer = self.serializer_class(obj, many=True, context={"request": request}) return ApiResponse.success( data=serializer.data, message=constants.SUCCESS, status=status.HTTP_200_OK ) @@ -1004,65 +1004,77 @@ class AgeGroupListView(APIView): class EventListView(generics.ListAPIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] - queryset = Event.objects.filter(active=True, draft=False, deleted=False, end_date__gte=timezone.now().date()) serializer_class = EventListSerializer filter_backends = [DjangoFilterBackend] filterset_class = EventFilter - def apply_popularity_latest(self, queryset, ordering): - # Split the ordering fields and remove any leading '-' characters - ordering_fields = [field.lstrip("-") for field in ordering.split(",")] - - # Check if 'nearest' is in the ordering fields and remove it as nearest work only for lat and longitude - if "nearest" in ordering_fields: - ordering.replace("nearest", "") - ordering_fields.remove("nearest") - - # Annotate the queryset with popularity if 'popularity' is in the ordering fields - if "popularity" in ordering_fields: - queryset = queryset.annotate(popularity=Count("interaction_event")) - - # Replace 'latest' with '-created_on' in the ordering fields - ordering = ",".join( - "start_date" if field == "latest" else f"-{field}" - for field in ordering_fields + def get_queryset(self): + # Base queryset filtering active, non-draft, non-deleted events with end date in the future + queryset = Event.objects.filter( + active=True, + draft=False, + deleted=False, + end_date__gte=timezone.now().date() ) - # If ordering is empty, set a default ordering - if not ordering: - ordering = "-start_date" + if not self.request.query_params: + preferences = PrincipalPreference.objects.get(principal=self.request.user) + preferred_categories_ids = preferences.preferred_categories.values_list( + "id", flat=True + ) + queryset = queryset.filter(category__in=preferred_categories_ids).order_by("start_date") - print(f"++++++++++++++++++++++++++++++++ordering data in populatirn flow {ordering}") - # Apply the ordering to the queryset - return queryset.order_by(*ordering.split(",")) + return queryset - def get_queryset(self): - queryset = super().get_queryset() + def filter_queryset(self, queryset): + queryset = super().filter_queryset(queryset) - # Sort by nearest location if latitude and longitude are provided - latitude = self.request.query_params.get("latitude") - longitude = self.request.query_params.get("longitude") - ordering = self.request.query_params.get("ordering", "") + # Get query parameters + latitude = self.request.query_params.get("latitude", "") + longitude = self.request.query_params.get("longitude", "") + ordering = self.request.query_params.get("sort", "") + # Handle nearest location sorting if latitude and longitude and "nearest" in ordering: - print("latitude fucntion called") - gmaps_service = GoogleMapsservice() - queryset = gmaps_service.get_nearest_events(queryset, float(latitude), float(longitude)) + queryset = self.apply_nearest_filter(queryset, latitude, longitude) - print(f"=======orderring data is {ordering}") + # Handle popularity and latest sorting + queryset = self.apply_sorting(queryset, ordering) + + return queryset + + def apply_nearest_filter(self, queryset, latitude, longitude): + gmaps_service = GoogleMapsservice() + return gmaps_service.get_nearest_events(queryset, float(latitude), float(longitude)) + + def apply_sorting(self, queryset, ordering): + # Split ordering fields and process each field + ordering_fields = [field.lstrip("-") for field in ordering.split(",")] + + # Remove 'nearest' from ordering as it's handled separately + if "nearest" in ordering_fields: + ordering_fields.remove("nearest") + ordering = ordering.replace("nearest", "") + + # Annotate with popularity and order it if requested + if "popularity" in ordering_fields: + queryset = queryset.annotate(popularity=Count("interaction_event")).order_by("-popularity") + + # order latest record and by default sorting + if "latest" in ordering_fields: + queryset = queryset.order_by("start_date") + + if "price" in ordering_fields: + queryset = queryset.order_by('entry_fee') - # Apply popularity annotation and ordering if requested - if ordering: - queryset = self.apply_popularity_latest(queryset, ordering) return queryset def get(self, request, *args, **kwargs): - print(f"getquery set data is {self.get_queryset()}") queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) - data = self.get_paginated_response(serializer.data) - return ApiResponse.success(message=constants.SUCCESS, data=data) + return self.get_paginated_response(serializer.data) + serializer = self.get_serializer(queryset, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) \ No newline at end of file diff --git a/manage_events/management/commands/test_facebook_api.py b/manage_events/management/commands/test_facebook_api.py new file mode 100644 index 0000000..5f0a2e3 --- /dev/null +++ b/manage_events/management/commands/test_facebook_api.py @@ -0,0 +1,30 @@ +import os +from django.conf import settings +from django.core.management.base import BaseCommand +from goodtimes.services import FacebookAPI, FacebookPoster +from ...models import Event + +class Command(BaseCommand): + help = 'Test facebook posting functionality' + + def handle(self, *args, **kwargs): + event = Event.objects.get(id=20) + if not event: + self.stdout.write(self.style.ERROR("No event found.")) + + if not event.image: + self.stdout.write(self.style.ERROR("No image found.")) + + image_path = f"{settings.BASE_DOMAIN}{event.image.url}" + print(f"complete path of image {image_path}") + caption = f"{event.title}\nDuration: {event.start_date} to {event.end_date}\nAddress: {event.venue.address}" + + facebook_api = FacebookAPI() + facebook_poster = FacebookPoster(facebook_api) + + response = facebook_poster.post_photo(image_path, caption) + + if response['success']: + self.stdout.write(self.style.SUCCESS(response['message'])) + else: + self.stdout.write(self.style.ERROR(response['message'])) diff --git a/manage_events/management/commands/test_instagram_api.py b/manage_events/management/commands/test_instagram_api.py new file mode 100644 index 0000000..a5c689e --- /dev/null +++ b/manage_events/management/commands/test_instagram_api.py @@ -0,0 +1,33 @@ +import os +from django.conf import settings +from django.core.management.base import BaseCommand +from goodtimes.services import InstagramAPI, InstagramPoster +from ...models import Event +import urllib.request + +class Command(BaseCommand): + help = 'Test Instagram posting functionality' + + def handle(self, *args, **kwargs): + event = Event.objects.get(id=20) + if not event: + self.stdout.write(self.style.ERROR("No event found.")) + + if not event.image: + self.stdout.write(self.style.ERROR("No image found.")) + + image_path = f"{settings.BASE_DOMAIN}{event.image.url}" + # image_path = event.image.url + print(f"complete path of image {image_path}") + + caption = f"{event.title}\nDuration: {event.start_date} to {event.end_date}\nAddress: {event.venue.address}" + + instagram_api = InstagramAPI() + instagram_poster = InstagramPoster(instagram_api) + + response = instagram_poster.post_image_with_caption(image_path, caption) + + if response['success']: + self.stdout.write(self.style.SUCCESS(response['message'])) + else: + self.stdout.write(self.style.ERROR(response['message'])) diff --git a/manage_events/management/commands/test_twitter_api.py b/manage_events/management/commands/test_twitter_api.py new file mode 100644 index 0000000..2c79553 --- /dev/null +++ b/manage_events/management/commands/test_twitter_api.py @@ -0,0 +1,28 @@ +import os +from django.core.management.base import BaseCommand +from goodtimes.services import TwitterAPI, TwitterPoster +from ...models import Event + +class Command(BaseCommand): + help = 'Test Twitter posting functionality' + + def handle(self, *args, **kwargs): + event = Event.objects.get(id=19) + if not event: + self.stdout.write(self.style.ERROR("No event found.")) + + if not event.image: + self.stdout.write(self.style.ERROR("No image found.")) + + image_path = event.image.path + caption = f"{event.title}\nDuration: {event.start_date} to {event.end_date}\nAddress: {event.venue.address}" + + twitter_api = TwitterAPI() + twitter_poster = TwitterPoster(twitter_api) + + response = twitter_poster.post_image_with_caption(image_path, caption) + + if response['success']: + self.stdout.write(self.style.SUCCESS(response['message'])) + else: + self.stdout.write(self.style.ERROR(response['message'])) diff --git a/manage_events/urls.py b/manage_events/urls.py index bcc3182..1f52b7b 100644 --- a/manage_events/urls.py +++ b/manage_events/urls.py @@ -99,4 +99,6 @@ urlpatterns = [ views.GenerateEventReportView.as_view(), name="generate_event_report", ), + + path("post-to-social-media///", views.SocialMediaPostView.as_view(), name="social_media_post") ] diff --git a/manage_events/views.py b/manage_events/views.py index 45184b1..939e708 100644 --- a/manage_events/views.py +++ b/manage_events/views.py @@ -1,5 +1,6 @@ from django.shortcuts import get_object_or_404, redirect, render from accounts import resource_action +from goodtimes.services import FacebookAPI, FacebookPoster, InstagramAPI, InstagramPoster, TwitterAPI, TwitterPoster from goodtimes.utils import JsonResponseUtil from manage_events.api.serializers import VenueSerializer, VenueShortSerializer from manage_events.forms import ( @@ -532,7 +533,7 @@ class CustomerVenueFilterView(LoginRequiredMixin, generic.View): User = get_user_model() from .report import generate_event_report, generate_event_report_pdf_three -from django.http import HttpResponse +from django.http import HttpResponse, JsonResponse class GenerateEventReportView(generic.View): @@ -553,3 +554,77 @@ class GenerateEventReportView(generic.View): response["Content-Disposition"] = f'attachment; filename="{filename}"' return response + +class SocialMediaPostView(generic.View): + def get(self, request, *args, **kwargs): + platform = kwargs.get("platform") + event_id = kwargs.get("id") + print(platform, event_id) + errors = [] + success_messages = [] + + try: + event = Event.objects.get(id=event_id) + except Event.DoesNotExist: + errors.append("Event does not exist") + return JsonResponse({ + 'message': "Error in posting to social media", + 'errors': errors, + 'success_messages': success_messages + }, status=400) + + if not event.active: + errors.append("Event is not active") + return JsonResponse({ + 'message': "Error in posting to social media", + 'errors': errors, + 'success_messages': success_messages + }, status=400) + + caption = f"{event.title}\nDuration: {event.start_date} to {event.end_date}\nAddress: {event.venue.address}" + + if platform in ['instagram', 'facebook', 'twitter', 'all']: + if platform in ['twitter', 'all']: + image_url = event.image.path + twitter_api = TwitterAPI() + twitter_poster = TwitterPoster(twitter_api) + result = twitter_poster.post_image_with_caption(image_url, caption) + if result['success']: + success_messages.append("Posted to Twitter successfully") + else: + errors.append("Fail to post on Twitter") + + image_url = request.build_absolute_uri(event.image.url) + if platform in ['facebook', 'all']: + facebook_api = FacebookAPI() + facebook_poster = FacebookPoster(facebook_api) + result = facebook_poster.post_photo(image_url, caption) + if result["success"]: + success_messages.append("Posted to Facebook successfully") + else: + errors.append("Fail to post on Facebook") + + if platform in ['instagram', 'all']: + instagram_api = InstagramAPI() + instagram_poster = InstagramPoster(instagram_api) + result = instagram_poster.post_image_with_caption(image_url, caption) + if result["success"]: + success_messages.append("Posted to Instagram successfully") + else: + errors.append("Fail to post on Instagram") + + if not errors: + return JsonResponse({'message': 'Post Successful', 'errors': errors, 'success_messages': success_messages}) + + if errors and success_messages: + return JsonResponse({ + 'message': 'Some posts succeeded while others failed', + 'errors': errors, + 'success_messages': success_messages + }, status=200) + + return JsonResponse({ + 'message': 'Error in posting to social media', + 'errors': errors, + 'success_messages': success_messages + }, status=400) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 3d196bc..f3ae9d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -69,8 +69,9 @@ sniffio==1.3.1 sqlparse==0.4.4 stripe==8.2.0 tqdm==4.66.2 +tweepy==4.14.0 Twisted==23.10.0 -# twisted-iocpsupport==1.0.4 +twisted-iocpsupport==1.0.4 txaio==23.1.1 typing_extensions==4.9.0 tzdata==2024.1 diff --git a/static/img/facebook.png b/static/img/facebook.png new file mode 100644 index 0000000..8400a87 Binary files /dev/null and b/static/img/facebook.png differ diff --git a/static/img/forward_all_icon.png b/static/img/forward_all_icon.png new file mode 100644 index 0000000..6b6f4d1 Binary files /dev/null and b/static/img/forward_all_icon.png differ diff --git a/static/img/instagram.png b/static/img/instagram.png new file mode 100644 index 0000000..b61a965 Binary files /dev/null and b/static/img/instagram.png differ diff --git a/static/img/x_twitter.png b/static/img/x_twitter.png new file mode 100644 index 0000000..62887fd Binary files /dev/null and b/static/img/x_twitter.png differ diff --git a/templates/manage_events/event_details.html b/templates/manage_events/event_details.html index e6fff65..7d5ed7a 100644 --- a/templates/manage_events/event_details.html +++ b/templates/manage_events/event_details.html @@ -2,12 +2,48 @@ {% load static %} {% block stylesheet %} + {% include "cdn_through_html/filepond_cdn_css.html" %} {% include "cdn_through_html/quill_cdn_css.html" %} {% include "cdn_through_html/tagify_cdn_css.html" %} +{% include "cdn_through_html/sweetalert2_cdn_css.html" %} {{form.media}} + + {% endblock %} {% block content %} @@ -25,15 +61,41 @@ {% endif %} -
-
-

{{ event.brand.title }}

-

{{ event.title }}

-

Description: {{ event.description }}

-

Created By: {{ event.created_by }}

+
+
+
+
+

{{ event.brand.title }}

+

{{ event.title }}

+

Description: {{ event.description }}

+

Created By: {{ event.created_by }}

+
+
+
+
+
+ +
+ +
@@ -145,4 +207,97 @@
-{% endblock content %} \ No newline at end of file +{% endblock content %} + +{% block javascript %} + + {% include "cdn_through_html/sweetalert2_cdn_js.html" %} + +{%endblock javascript%} \ No newline at end of file