Skip to content
This repository has been archived by the owner on Aug 12, 2024. It is now read-only.

Commit

Permalink
Merge pull request #27 from quintindunn/structure-refactor
Browse files Browse the repository at this point in the history
Structure refactor
  • Loading branch information
quintindunn authored Oct 27, 2023
2 parents 88bb1b3 + 8d68fbb commit 8e12b4f
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 83 deletions.
14 changes: 14 additions & 0 deletions examples/send_kudos/send_kudos_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import os
from PIL import Image
from lapsepy.lapse import Lapse

if __name__ == '__main__':
lapse = Lapse(refresh_token=os.getenv("REFRESH_TOKEN"))

# Develop in 15 seconds
friend_id = input("Friend UUID: ")

# Get friend object
friend = lapse.get_profile_by_id(friend_id)

lapse.send_kudos(user=friend)
17 changes: 17 additions & 0 deletions lapsepy/journal/factory/friends_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,20 @@ def _render_variables(self):
"mutualLimit": self.mutual_limit,
"popularLimit": self.popular_limit
}


class SendKudosGQL(BaseGQL):
def __init__(self, user_id: str):
super().__init__("SendKudosGraphQLMutation", "mutation SendKudosGraphQLMutation($input: SendKudosInput!) "
"{ sendKudos(input: $input) { __typename success } }")

self.user_id = user_id

self.variables = {}

self._render_variables()

def _render_variables(self):
self.variables['input'] = {
"id": self.user_id
}
19 changes: 17 additions & 2 deletions lapsepy/journal/journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@

import requests

from .factory.friends_factory import FriendsFeedItemsGQL, ProfileDetailsGQL
from .factory.friends_factory import FriendsFeedItemsGQL, ProfileDetailsGQL, SendKudosGQL
from .factory.media_factory import ImageUploadURLGQL, CreateMediaGQL, SendInstantsGQL
from lapsepy.journal.factory.profile_factory import SaveBioGQL, SaveDisplayNameGQL, SaveUsernameGQL, SaveEmojisGQL, \
SaveDOBGQL

from .structures import Profile, Snap
from .structures.snap import Snap
from .structures.profile import Profile

import logging

Expand Down Expand Up @@ -178,6 +179,20 @@ def upload_instant(self, im: Image.Image, user_id: str, file_uuid: str | None =
time_limit=time_limit).to_dict()
self._sync_journal_call(query)

def send_kudos(self, user_id: str):
"""
Sends kudos (vibes) to a given user
:param user_id: id of the user to send kudos to.
:return:
"""
query = SendKudosGQL(user_id=user_id).to_dict()
response = self._sync_journal_call(query)

if not response.get("data", {}).get("sendKudos", {}).get("success"):
raise SyncJournalException("Error sending kudos, could you already have reached your daily limit?")



def get_friends_feed(self, count: int = 10) -> list[Profile]:
"""
Gets your friend upload feed.
Expand Down
94 changes: 94 additions & 0 deletions lapsepy/journal/structures/profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import io
import logging
import requests

from datetime import datetime
from PIL import Image

from .snap import Snap

logger = logging.getLogger("lapsepy.journal.structures.py")


def _dt_from_iso(dt_str: str):
return datetime.fromisoformat(dt_str)


class Profile:
def __init__(self, user_id: str, username: str, display_name: str, profile_photo_name: str, bio: str | None,
emojis: list[str], is_friends: bool, blocked_me: bool, kudos: int, tags: list[dict],
is_blocked: bool = False, friends: list["Profile"] = None):
if friends is None:
friends = []

self.bio: str = bio
self.blocked_me: bool = blocked_me
self.user_display_name: str = display_name
self.emojis: list[str] = emojis
self.is_friends: bool = is_friends
self.kudos = kudos
self.profile_photo_name: str = profile_photo_name
self.tags = tags
self.user_id: str = user_id
self.username: str = username
self.media: list[Snap] = []
self.is_blocked = is_blocked

self.friends: list["Profile"] = friends

self.profile_picture: Image.Image | None = None

@staticmethod
def from_dict(profile_data: dict) -> "Profile":
"""
Generates a Profile object from a dictionary with the necessary profile data
:param profile_data: Dictionary containing the necessary data.
:return: Profile object prefilled with the data.
"""
logger.debug("Creating new Profile object from dictionary.")

pd = profile_data
return Profile(
bio=pd.get('bio'),
blocked_me=pd.get('blockedMe'),
display_name=pd.get('displayName'),
emojis=pd.get("emojis", {}).get("emojis"),
is_friends=pd.get("friendStatus") == "FRIENDS",
kudos=pd.get("kudos", {}).get("totalCount", -1),
profile_photo_name=pd.get('profilePhotoName'),
tags=pd.get("tags"),
user_id=pd.get('id'),
username=pd.get('username'),
)

def load_profile_picture(self, quality: int = 100, height: int | None = None) -> Image.Image:
"""
Loads the Profile's profile picture into memory by making an HTTP request to Lapse's servers.
:param quality: Quality of the image (1-100)
seek https://cloudinary.com/documentation/transformation_reference#q_quality for more information.
:param height: Height of the image in pixels, width is determined by image aspect ratio. Leave as None to get
original height.
:return: Pillow image.
"""
url = f"https://image.production.journal-api.lapse.app/image/upload/q_{quality}"
url += f",h_{height}" if height is not None else ""
url += f"//{self.profile_photo_name}.jpg"

logger.debug(f"Getting profile image from \"{url}\"")

request = requests.get(url)
bytes_io = io.BytesIO(request.content)
image = Image.open(bytes_io)

self.profile_picture = image

return image

def send_instant(self, ctx, im: Image, file_uuid: str | None = None, im_id: str | None = None,
caption: str | None = None, time_limit: int = 10):
return ctx.upload_instant(im=im, user=self, file_uuid=file_uuid, im_id=im_id, caption=caption,
time_limit=time_limit)

def __str__(self):
return f"<Lapse profile \"{self.username}\" {self.user_id}>"
Original file line number Diff line number Diff line change
Expand Up @@ -17,86 +17,6 @@ def _dt_from_iso(dt_str: str):
return datetime.fromisoformat(dt_str)


class Profile:
def __init__(self, user_id: str, username: str, display_name: str, profile_photo_name: str, bio: str | None,
emojis: list[str], is_friends: bool, blocked_me: bool, kudos: int, tags: list[dict],
is_blocked: bool = False, friends: list["Profile"] = None):
if friends is None:
friends = []

self.bio: str = bio
self.blocked_me: bool = blocked_me
self.user_display_name: str = display_name
self.emojis: list[str] = emojis
self.is_friends: bool = is_friends
self.kudos = kudos
self.profile_photo_name: str = profile_photo_name
self.tags = tags
self.user_id: str = user_id
self.username: str = username
self.media: list[Snap] = []
self.is_blocked = is_blocked

self.friends: list["Profile"] = friends

self.profile_picture: Image.Image | None = None

@staticmethod
def from_dict(profile_data: dict) -> "Profile":
"""
Generates a Profile object from a dictionary with the necessary profile data
:param profile_data: Dictionary containing the necessary data.
:return: Profile object prefilled with the data.
"""
logger.debug("Creating new Profile object from dictionary.")

pd = profile_data
return Profile(
bio=pd.get('bio'),
blocked_me=pd.get('blockedMe'),
display_name=pd.get('displayName'),
emojis=pd.get("emojis", {}).get("emojis"),
is_friends=pd.get("friendStatus") == "FRIENDS",
kudos=pd.get("kudos", {}).get("totalCount", -1),
profile_photo_name=pd.get('profilePhotoName'),
tags=pd.get("tags"),
user_id=pd.get('id'),
username=pd.get('username'),
)

def load_profile_picture(self, quality: int = 100, height: int | None = None) -> Image.Image:
"""
Loads the Profile's profile picture into memory by making an HTTP request to Lapse's servers.
:param quality: Quality of the image (1-100)
seek https://cloudinary.com/documentation/transformation_reference#q_quality for more information.
:param height: Height of the image in pixels, width is determined by image aspect ratio. Leave as None to get
original height.
:return: Pillow image.
"""
url = f"https://image.production.journal-api.lapse.app/image/upload/q_{quality}"
url += f",h_{height}" if height is not None else ""
url += f"//{self.profile_photo_name}.jpg"

logger.debug(f"Getting profile image from \"{url}\"")

request = requests.get(url)
bytes_io = io.BytesIO(request.content)
image = Image.open(bytes_io)

self.profile_picture = image

return image

def send_instant(self, ctx, im: Image, file_uuid: str | None = None, im_id: str | None = None,
caption: str | None = None, time_limit: int = 10):
return ctx.upload_instant(im=im, user=self, file_uuid=file_uuid, im_id=im_id, caption=caption,
time_limit=time_limit)

def __str__(self):
return f"<Lapse profile \"{self.username}\" {self.user_id}>"


class Snap:
BASE_URL = "https://image.production.journal-api.lapse.app/image/upload/"

Expand Down
13 changes: 12 additions & 1 deletion lapsepy/lapse/lapse.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from lapsepy.auth.refresher import refresh
from lapsepy.journal.journal import Journal
from lapsepy.journal.common.exceptions import AuthTokenExpired
from lapsepy.journal.structures import Profile
from lapsepy.journal.structures.profile import Profile

import logging

Expand Down Expand Up @@ -86,6 +86,17 @@ def upload_instant(self, im: Image, user: str | Profile, file_uuid: str | None =
return self.journal.upload_instant(im=im, user_id=user, file_uuid=file_uuid, im_id=im_id, caption=caption,
time_limit=time_limit)

def send_kudos(self, user: str | Profile):
"""
Sends kudos (vibes) to a user.
:param user: ID / Object of user to send it to.
:return:
"""
if isinstance(user, Profile):
user = user.user_id

self.journal.send_kudos(user)

def get_friends_feed(self, count: int = 10):
"""
Gets your friend upload feed.
Expand Down

0 comments on commit 8e12b4f

Please sign in to comment.