Customer Milestone 3 Report - bounswe/bounswe2024group11 GitHub Wiki
This is the third milestone report for the bounswe2024group11
team.
It includes a summary of what we have done, the implementation of the deployed application, the final design diagrams, final project plan in a detailed manner, lessons we have learnt, difficulties we have faced, work done by each team member, and the tools we have benefitted.
At the end of the report, we have dedicated a section for our self evaluation.
This project aims to build a comics-specific semantic information browser (SIB). Users will be able to create posts and search for them. The system will use Wikidata API to support the semantic searching of posts as well as enrich the app by providing metadata information.
Users will be able to register and login to the system so that they can make a short post, bookmark or like posts. They will also be able to see those who posted or liked content and follow them.
The system will use Wikidata API to make semantic queries to the Wikidata Database. Utilizing "subject-predicate-object" nature of these SPARQL queries, the system can search for objects that has semantic relations.
Our solution will provide an API that will be used by Web and Mobile clients. Hence, the system will provide a web and a mobile application.
-
1.1.1 Account Requirements
-
1.1.1.1 Users shall be able to register the system by providing a username, email, and password.
-
1.1.1.2 Registered users shall be able to log in to the system by providing username and password.
-
1.1.1.5 Registered users shall be able to log out from the system.
-
1.1.1.6 Registered users should have a profile page.
- 1.1.1.6.1 Registered users should be able to edit their profile.
- 1.1.1.6.2 Registered users should be able to put up a profile picture.
- 1.1.1.6.3 Registered users should be able to put up a biography.
-
-
1.1.2 Post Requirements
-
1.1.2.1 Create
- 1.1.2.1.1 Registered users shall be able to create posts by providing a title and text.
- 1.1.2.1.2 The post author should be able to provide an image for the post.
- 1.1.2.1.3 Users shall be able to see the author of the post.
- 1.1.2.1.4 Users shall be able to link their posts to a comics item by providing a tag
-
1.1.2.2 Like
- 1.1.2.2.1 Users shall be able to see how many people have liked the post.
- 1.1.2.2.2 Users shall be able to see who liked the post.
- 1.1.2.2.3 Registered users shall be able to like a post.
-
1.1.2.4 Bookmark
- 1.1.2.4.1 Users should be able to see how many people have bookmarked the post.
- 1.1.2.4.2 Registered users shall be able to bookmark a post.
-
-
1.1.3 User-to-User Interaction Requirements
- 1.1.3.1.1.2 Users shall be able to see how many people follow a registered user.
- 1.1.3.1.1.4 Users shall be able to see how many people a registered user follows.
- 1.1.3.2 User-to-System Interactions
- 1.1.3.2.1 Users shall be able to search for posts.
- 1.1.4 Searching and Browsing Requirements
- 1.1.4.1 Users shall be able to search for posts by semantic searching.
- 1.1.4.2 Users shall be able to see metadata information that the post is related to.
-
1.2.1 Semantic Search
- 1.2.1.1 The system shall be able to query wikidata API search with specific keywords.
-
1.2.2 Feed
- 1.2.2.1 The system should provide a feed for users.
- 1.2.2.1.2 The system should show the registered user's followings' recently published posts to the registered user.
- 1.2.2.1 The system should provide a feed for users.
-
1.2.3 Authentication
- 1.2.3.1 The system shall only allow a username and an email address that is not used before upon registration.
- 1.2.3.3 The system shall hash users' authentication information.
- 2.1.1
- 2.1.1.1 The system-user interaction should respond in an acceptable time.
- 2.1.1.2 The system-network interaction should result in an acceptable time.
-
2.2.1 Authentication
- 2.2.1.1 The system should implement password-based authentication.
-
2.2.2 Auhtorization
- 2.2.2.1 The system should prevent unauthorized access to accounts.
-
1.1.1 Account Requirements
- 1.1.1.1 Users shall be able to register the system by providing a username, email, and password.
- 1.1.1.2 Registered users shall be able to log in to the system by providing username and password.
- 1.1.1.5 Registered users shall be able to log out from the system.
- 1.1.1.6 Registered users should have a profile page.
-
1.1.2 Post Requirements
- 1.1.2.1 Create
- 1.1.2.1.3 Users shall be able to see the author of the post.
- 1.1.2.1 Create
- 1.2.2 Feed
- 1.2.2.1 The system should provide a feed for users.
- 1.2.2.1.2 The system should show the registered user's followings' recently published posts to the registered user.
- 1.2.2.1 The system should provide a feed for users.
- 1.2.3 Authentication
- 1.2.3.1 The system shall only allow a username and an email address that is not used before upon registration.
- 1.2.3.3 The system shall hash users' authentication information.
- Emre registers to the app.
- Emre uses his credentials to login.
- Emre looks his profile. He decides to edit the profile, so he clicked to edit button.
- Emre adds some details about him and submits.
- Emre finally sees his new profile.
-
Mücahit is already logged in.
-
Mücahit wants to search some posts related to the enemies of its favorite comic character. He chooses over categories in the search page.
- Mücahit writes his favorite character to the search bar and looks for suggestions.
- Mücahit gets the search results about the enemies.
-
Ozan has already logged in.
-
Ozan wants to share his ideas, so he creates a new post.
- Ozan fills the contents and add a tag by using the given suggestions.
- Ozan submits the post and tries to find some metadata for his post. He enters the search bar and searches by occupation.
- Ozan finds his post, sees the Wikidata information and likes and bookmarks his own post.
- Ozan then wants to look who liked his post. However, the post is newly he is the only one who liked the post.
- Hasan has already logged in.
- He wants to see posts about superheros that are also detectives.
- He selects the occupation category and searches for detective occupation.
- He sees the posts that are related to superheroes that are detectives.
- He learns that a superhero called Batman is a detective. As Hasan has detective curiosity, he wants to learn Batman's real name and where he was born. So, he enters the post.
- He learns Batman's real name and his birth place.
- He wants to see the post owner's profile. Clicks the owner on up-left.
- Hasan wants to test this app so he registers to the app using tester2024 as username and password from the web.
- Then he logs in using his credentials.
- He can see his feed.
- Emre logs in to the app using his credentials (tenacke as username and password).
- He can see his feed.
- Release Tag: Please follow the link to Group11-Practice-App-Release-v0.2.
- Web Application: Please follow the link to Zenith Web Application.
- Mobile Application: Download for APK is available under our release tag, please follow the link to Zenith Mobile Application.
- Project Github Repository
- Backend Code of the Project
- Frontend/Web Code of the Project
- Mobile Code of the Project
- Swagger for API Documentation
Requirements
Designs
Project Plan
- Backend Meeting #6 : Discussion of further work to do on backend.
- Weekly Sync #16 : Sync between frontend and backend.
- Mobile Meeting #2 : Distribution of tasks in mobile part.
- Backend Meeting #7 : Distribution of endpoint implementation and their tests.
- You can refer to the detailed guide in README file in the project repository for deploying and testing the application on your local environment or another host machine.
- Do not use the mobile application in dark mode. The components in mobile side are rendered with respect to light mode of Android. Some additional libraries used in this project may be sensitive to the theme changes and may cause render complications. Some icons may not be seen and user experience may be terrible.
- You can use the test user
@ozankrk
.
username : ozankrk
password : ozibaba
- Time management was one of the most difficult challenges. Since most of the team members had no experience on software development, learning and implementing take a lot of time. However, we attend classes and also have other responsibilites, we could not get to the end of the project.
- There was no one experienced on the backend team. On top of that, they started to implement the app, without learning core concepts of Django REST Framework. To mitigate this, one of them prepared tutorials on Django REST Framework and relationships of its components and presented to the team.
- Since team members lacked theoretical information about Django REST, they were unable to build on top of the project that was built before Milestone 2. Therefore, they trashed it and started from the start.
- Building a solip API that contains the essential info needed by frontend team was hard as well.
- Before implementation, learn the core concepts of the programming language/framework.
- Trashing what is already done could be a reasonable decision sometimes and sometimes not. If the milestone is close, the latter may be true.
- Most of the time, time management will be a problem. Try to foresee what should be done at what time and plan accordingly.
- As per backend part, first document the API that is to be built. Then write unit tests for that API. Thirdly, implement the API. Lastly, make further adjustments on the API. This helps to build a more collaborative development with the frontend team since they can develop their codes more time efficient. Otherwise, the two teams would have to continuously communicate and waste time during the integration of the backend to the frontend.
- We should respect our UI designs to see what are the requirements on the web and mobile parts of the application.
- We can reflect the opinion that project planning and being loyal to the project plan during whole development process is the key for developing a comprehensive good work instead of using the power of the customer deadlines.
- Our communication inside the team was one of our strengths. Even if we are divided into three teams as backend, frontend and mobile, we should have kept communication inside the team during our implementation process. Of course, the lack of communication compared to before milestone was natural due to time-pressure that all three teams faced during the Milestone 3 preparation.
- You can view each team member's biographies & personal efforts page here.
Need to be Revised
- Updating UML Diagrams
- Dockerization & Deployment of Web Application
- Issue3](https://github.com/bounswe/bounswe2024group11/issues/458)
- Merge Backend v2: We have developed and tested an alternative backend after facing some seriuous issues on the previous one without deleting it. This PR brings the new backend to the old pipeline. This is probably the most important PR of theis project.
- Merge develop-backend into backend
- add authorization rules and unique constraints for like, bookmark and follow endpoints
Need to be Revised
- I haven't prepared any wiki documentation for describing my contributions, however, I have prepared a README file for root directory of our repository which describes the steps of the deployment of the application for building and running the application.
I have contributed to the implementation of some ViewSets and some APIViews, which play significant role on the functionality of the backend service. Here is the full list of the endpoints I've implemented/contributed to the implementation:
- PostViewSet
- LikeViewSet
- BookmarkViewSet
- FollowViewSet
- UserViewSet
- UserProfileView
- UserRegistrationView
Viewsets are great for handling CRUD operations for models. These viewsets encapsulated the logic for querying and manipulating the data, providing a clean and organized structure for the backend code. This modular approach also facilitated easier maintenance and expansion of the API functionalities. This is why I chose to go with ViewSets for most of the endpoints.
Also, I define routes for the ViewSets by using rest_framework's DefaultRouter object, which simplifies the URL definitions of a ViewSet and standardizes URL definitions across the ViewSets.
Here is a basic example:
If you define your ViewSet like the following example,
from django.urls import path
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r"posts", PostViewSet)
# router.register(r"likes", LikeViewSet) # you can add other ViewSet routes similarly
urlpatterns = [
path("", include(router.urls)),
... # define your other routes
]
Then, you can reach the following endpoints immediately,
-
/posts/
withPOST
method to create new Post objects -
/posts/
withGET
method to list all Post objects -
/posts/<id>/
withGET
method to retrieve a specific Post object -
/posts/<id>/
withPUT
orPATCH
methods to fully or partially update a specific Post object, respectively -
/posts/<id>/
withDELETE
method to delete a specific Post object
- This endpoint is used to create, list, retrieve, update, and delete the Posts.
- Following steps demonstrate an example for each of them.
A new post can be created by calling the following endpoint.
curl -X POST http://164.90.189.150/api/v2/posts/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
-d '{
"title": "Spiderman",
"content":"The revenge of the Spiderman will be great...",
"image_src": "https://unsplash.com/photos/a-close-up-of-a-spider-man-with-glowing-eyes-PXjQaGxi4JA",
"qid": "Q79037",
"qtitle": "Spider-Man"
}'
Below, you can see the response of this API call.
{
"id": 22,
"author_profile": {
"id": 6,
"username": "memin41",
"email": "[email protected]",
"fullname": "Muhammet",
"picture": "https://i.ibb.co/kHBtv0g/zenith.png",
"biography": "Please update your biography."
},
"like_count": 0,
"bookmark_count": 0,
"liked_by": [],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "Spiderman",
"content": "The revenge of the Spiderman will be great...",
"image_src": "https://unsplash.com/photos/a-close-up-of-a-spider-man-with-glowing-eyes-PXjQaGxi4JA",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-19T07:27:28.301442Z",
"updated_at": "2024-05-19T07:27:28.301486Z",
"author": 6
}
You can retrieve the information about a post by calling the following endpoint with the ID of the post, which is 22
in our example.
You can find the ID of your newly created post from the response of the previous create command. The
id
is the field you need to look at.
curl -X GET http://164.90.189.150/api/v2/posts/22/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
Below, you can see the response of this API call.
{
"id": 22,
"author_profile": {
"id": 6,
"username": "memin41",
"email": "[email protected]",
"fullname": "Muhammet",
"picture": "https://i.ibb.co/kHBtv0g/zenith.png",
"biography": "Please update your biography."
},
"like_count": 0,
"bookmark_count": 0,
"liked_by": [],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "Spiderman",
"content": "The revenge of the Spiderman will be great...",
"image_src": "https://unsplash.com/photos/a-close-up-of-a-spider-man-with-glowing-eyes-PXjQaGxi4JA",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-19T07:27:28.301442Z",
"updated_at": "2024-05-19T07:27:28.301486Z",
"author": 6
}
You can get the all posts by calling the following endpoint.
Please note that we've override the default
GET
function of the ViewSet, so this endpoint does not return all posts actually. Instead, it returns all the posts the current user creates and the posts from the people he follows. In other words, this endpoint returns the posts the user created and the feed he will see in the home page.
curl -X GET http://164.90.189.150/api/v2/posts/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
Below, you can see the response of this API call. Since this user has some previous actions, it returns other posts as well. Please identify the post we just created at the end.
[
{
"id": 4,
"author_profile": {
"id": 6,
"username": "memin41",
"email": "[email protected]",
"fullname": "Muhammet",
"picture": "https://i.ibb.co/kHBtv0g/zenith.png",
"biography": "Please update your biography."
},
"like_count": 1,
"bookmark_count": 0,
"liked_by": [
"umit"
],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "The Amazing Spider-Man: Birth of Venom",
"content": "Dive into the origin story of one of Spider-Man's most formidable foes, Venom. This collection includes the first appearance of the black suit that eventually becomes Venom, offering a thrilling journey through Spidey's battles with this iconic villain.",
"image_src": "https://www.marvel.com/comics/collection/2275/the_amazing_spider-man_birth_of_venom_trade_paperback",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-17T06:30:34.632861Z",
"updated_at": "2024-05-17T06:30:34.632910Z",
"author": 6
},
{
"id": 5,
"author_profile": {
"id": 6,
"username": "memin41",
"email": "[email protected]",
"fullname": "Muhammet",
"picture": "https://i.ibb.co/kHBtv0g/zenith.png",
"biography": "Please update your biography."
},
"like_count": 3,
"bookmark_count": 1,
"liked_by": [
"memin41",
"ozankrk",
"Tatü"
],
"is_liked": true,
"is_bookmarked": false,
"is_following": false,
"title": "My Favorite Spider-Man Story Arc",
"content": "Just finished reading \"The Amazing Spider-Man: Birth of Venom\" and it was incredible! The origin of Venom is so well done, and the black suit saga is a must-read for any Spidey fan. Highly recommend it!",
"image_src": "https://www.artmajeur.com/medias/standard/k/o/konstantin1/artwork/17051995_f1a1bdec-1101-445e-b9b9-cb1f195c6981.jpg",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-17T06:51:49.392587Z",
"updated_at": "2024-05-17T06:51:49.392650Z",
"author": 6
},
...
...
{
"id": 22,
"author_profile": {
"id": 6,
"username": "memin41",
"email": "[email protected]",
"fullname": "Muhammet",
"picture": "https://i.ibb.co/kHBtv0g/zenith.png",
"biography": "Please update your biography."
},
"like_count": 0,
"bookmark_count": 0,
"liked_by": [],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "Spiderman",
"content": "The revenge of the Spiderman will be great...",
"image_src": "https://unsplash.com/photos/a-close-up-of-a-spider-man-with-glowing-eyes-PXjQaGxi4JA",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-19T07:27:28.301442Z",
"updated_at": "2024-05-19T07:27:28.301486Z",
"author": 6
}
]
Content of a post can be updated by using the following endpoint. You can either a partial or a full update. A simple partial update example is here:
curl -X PATCH http://164.90.189.150/api/v2/posts/22/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
-d '{
"content":"The biggest revenge: Rise of the Spiderman"
}'
Below, you can see the response of this API call.
{
"id": 22,
"author_profile": {
"id": 6,
"username": "memin41",
"email": "[email protected]",
"fullname": "Muhammet",
"picture": "https://i.ibb.co/kHBtv0g/zenith.png",
"biography": "Please update your biography."
},
"like_count": 0,
"bookmark_count": 0,
"liked_by": [],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "Spiderman",
"content": "The biggest revenge: Rise of the Spiderman",
"image_src": "https://unsplash.com/photos/a-close-up-of-a-spider-man-with-glowing-eyes-PXjQaGxi4JA",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-19T07:27:28.301442Z",
"updated_at": "2024-05-19T07:52:39.680687Z",
"author": 6
}
A specific Post can be deleted by calling the following endpoint with the Post id, which is 22
in this example.
curl -X DELETE http://164.90.189.150/api/v2/posts/22/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
Below, you can see the response of this API call.
{
"res": "Post deleted successfully."
}
- This endpoint is used to create and delete Like objects. In other words, like and unlike a post.
- Following steps demonstrate an example for each of them.
A post can be liked by calling the following endpoint with the Id of the Post you want to like, which is 23
in this example.
curl -X POST http://164.90.189.150/api/v2/likes/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
-d '{
"post": "23"
}'
Below, you can see the response of this API call.
{
"id": 24,
"created_at": "2024-05-19T08:02:31.668395Z",
"user": 6,
"post": 23
}
A previously liked Post can be unliked by calling the following endpoint with the Like object id, which is 24
in this example.
curl -X DELETE http://164.90.189.150/api/v2/posts/24/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
This endpoint returns a 204
response without a body.
- This endpoint is used to create and delete Bookmark objects. In other words, bookmark and unbookmark a post.
- Following steps demonstrate an example for each of them.
A post can be bookmarked by calling the following endpoint with the Id of the Post you want to bookmark, which is 23
in this example.
curl -X POST http://164.90.189.150/api/v2/likes/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
-d '{
"post": "23"
}'
Below, you can see the response of this API call.
{
"id": 10,
"created_at": "2024-05-19T08:10:15.381830Z",
"user": 6,
"post": 23
}
A previously bookmarked Post can be unbbokmarked by calling the following endpoint with the Bookmark object id, which is 10
in this example.
curl -X DELETE http://164.90.189.150/api/v2/posts/10/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
This endpoint returns a 204
response without a body.
- This endpoint is used to create and delete Follow objects. In other words, follow and unfollow a user.
- Following steps demonstrate an example for each of them.
A user can be followed by calling the following endpoint with the ID of the user you want to follow, which is 17
in this example.
curl -X POST http://164.90.189.150/api/v2/follows/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
-d '{
"following": "17"
}'
Below, you can see the response of this API call.
{
"id": 14,
"follower_username": "memin41",
"following_username": "jonathan",
"created_at": "2024-05-19T08:17:20.961809Z",
"follower": 6,
"following": 17
}
A previously followed user can be unfollowed by calling the following endpoint with the User ID, which is 17
in this example.
curl -X DELETE http://164.90.189.150/api/v2/follows/17/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
This endpoint returns a 204
response without a body.
- This endpoint is used to create a new user.
- Following steps demonstrate an example for it.
A user can be created by calling the following endpoint.
curl -X POST http://164.90.189.150/api/v2/register/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"
-d '{
"username":"jonathan",
"email":"[email protected]",
"fullname": "Jonathan Hogwards ",
"password":"mattmatt"
}'
Below, you can see the response of this API call.
{
"username": "jonathan",
"email": "[email protected]"
}
Please note that I don't demonstrate how to use UserViewSet and UserProfile APIView since they are not used by the client applications. Our backend use their serializers inside other serializers. The view of them are created for checking and debugging purposes only.
- Identify the non-functional requirements. issue
- This issue contains the identification of non-functional requirements in our Zenith app. I didn't have any idea on what non-functional requirements could be. I did a research on other applications. I tried to keep it simple and understandable as possible. I communicated with my teammates Mücahit and Emre to reach the final form of non-functional requirements.
- Connect the backend to hosted database. issue
- This issue contains the work on connecting the backend to hosted database. In our app, we tried to keep the security at its maximized level. In order to reach this goal we used 1password. With this website, we shared our database info in a secured way. By changing the databases section in settings.py of our app's django folder, we connected the backend with our database. I communicated with Muhammed Emin Arayıcı in this issue. He helped me a lot to get a knowledge on database interconnection.
- Implement proper response codes on endpoints. issue
- This issue contains the work on modifying the default response codes on signup and login mechanisms in our app. Our mechanism were returning response code as 404 when we weren't doing login correctly and 500 when we weren't doing signup correctly. I researched the response code in order to apply this in our API. We had
get_object_or_404
previously. We had to change each of it with another proper response code. This issue helped me to have an idea on the specifications on response codes. I communicated with my teammate Mücahit when I was dealing with this issue. We changed the API structure and wrote the unit test.
- This issue contains the work on modifying the default response codes on signup and login mechanisms in our app. Our mechanism were returning response code as 404 when we weren't doing login correctly and 500 when we weren't doing signup correctly. I researched the response code in order to apply this in our API. We had
- feat: connect backend to hosted MySQL server. PR
- This PR contains the work of connecting backend to hosted database. With its merge, backend was connected to hosted database properly and in a secured way. I communicated with Muhammed Emin Arayıcı on understanding the behavior.
- feat(backend): send proper respond status codes. PR
- This PR contains the work of modifying the response codes to proper ones. I communicated with Mücahit Erdoğan Ünlü on implementing new API endpoints. and writing new unit tests.
- fix(backend): add authorization rules and unique constraints for like, bookmark and follow endpoints. PR
- This PR contains the work of adding authorization rules and unique constraints for like, bookmark and follow endpoints. With this PR, multiple like, bookmark on a same post and multiple follow to a same user is prevented. I communicated with Muhammed Emin Arayıcı on implementing this precautions.
- Meeting Notes:
- Requirements:
- I documented the non-functional requirements.
- How to Connect Django to MySQL
- I wrote a simple document on how to connect Django to MySQL.
- Well Designed Documented API
- Open API Specifications as in Swagger UI
- I wrote a document on the basic Open API specifications as in Swagger UI which we used in order to implement our API's.
- How to Store Image Fields
- I wrote a document on how to store image fields in our app. But we preferred the way of adding URL's. So this documentation was never used.
- I have implemented viewSet definitions of like, bookmark and follow with Muhammed Emin Arayıcı. This viewSet's were compatible with functional requirements which was written by Emre Kılıç and Mücahit Erdoğan Ünlü.
class LikeViewSet(viewsets.ModelViewSet):
queryset = Like.objects.all()
serializer_class = LikeSerializer
permission_classes = [permissions.IsAuthenticated, IsUserOwnerOrReadOnly]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class BookmarkViewSet(viewsets.ModelViewSet):
queryset = Bookmark.objects.all()
serializer_class = BookmarkSerializer
permission_classes = [permissions.IsAuthenticated, IsUserOwnerOrReadOnly]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class FollowViewSet(viewsets.ModelViewSet):
queryset = Follow.objects.all()
serializer_class = FollowSerializer
permission_classes = [permissions.IsAuthenticated, IsFollowerOwnerOrReadOnly]
def get_object(self):
queryset = self.get_queryset()
obj = get_object_or_404(queryset, follower=self.request.user, following__id=self.kwargs['pk'])
return obj
def destroy(self, request, *args, **kwargs):
follow = self.get_object()
if follow.follower != request.user:
return Response(status=status.HTTP_403_FORBIDDEN)
else:
self.perform_destroy(follow)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_create(self, serializer):
serializer.save(follower=self.request.user)
- Those view sets are connected to these endpoints:
router.register(r"likes", LikeViewSet)
router.register(r"bookmarks", BookmarkViewSet)
router.register(r"follows", FollowViewSet)
- We used permissions in order to control the authorization on multiple liking, bookmarking on a single post and multiple following on a single user.
class IsAuthorOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.author == request.user
class IsUserOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.user == request.user
class IsFollowerOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.follower == request.user
class IsProfileOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user
- These functions were tested manually. So we didn't need a unit test.
-
I didn't have any experience on working as a team in a software development project. Getting to know each members and their strengths and weaknesses was a field that I wasn't experienced on. But when 10 people gather in a positive attitude to make things happen, walls will fall down. Each member of our team had the great disipline to accomplish their tasks. Sometimes we slept shorter hours, couldn't pay attention to other classes efficiently and so on. But we learned what does it take to become a valuable team member.
-
Developing in backend was a new subject for me because I didn't have any experience on backend developing. I have always suspected this area of being more boring and sophisticated when comparing with mobile and web developing. But it turned out that backend developing was really not that horrible as it looked. I truly believe that I gained valuable experience on backend developing. I may follow the paths of being a backend developer in the future.
-
Update Project Plan: issue #278
- This issue covers how as a team we created our project plan's final form. As the team member who was responsible for a well documented project plan, I communicated with my team mates from other teams: Ozan form backend team and Hasan Kerem from web team. In the end, we were able to reach the current form of our project plan.
-
Implement a Post Creation Screen for Mobile: issue #353
- This issue covers the implementation of post creation screen. After the implementation of post component and post screen, the next step was the creation screen of this newly created post component. Step by step aproach made the implementation of these components easier.
-
Implement Edit Post Screen for Mobile: issue #386
- This issue covers the implementation of post edit screen. After the creation implementation of a post, edit feature was added to the system, though it is not fully functioning.
-
feat: added edit post: PR #391
- This pull request covers the implementation of edit post feature. With this merge, updating a post attribute has been added to the system.
-
feat: created profile page: PR #367
- This pull request covers the implementatino of profile page of an user. A registered user is able to see his/her profile page with the information of himself/herself. The profile page will not be loaded as long as there is none registered user on the system.
-
feat: implemented signup and login: PR #314
- This pull request covers the implementation of login and registration functions of a user. In order to be the part of the database and benefit the properties of it, users must be registered to system and after that they must be logged in. These critical steps had been implemented and merged to the sytem with the mentioned PR.
- Project Plan: Wiki Page
- This wiki page contains the final form of the project plan.
- Mobile Meeting Notes 2: Wiki Page
- This wiki page contains the meeting notes for mobile meeting 2.
-
I have helped and contributed the implementation of
/api/v2/mute/
endpoint, however we were not able to implement this particular endpoint on web and mobile. I can still provide the implementation of the endpoint. Please take into consideration that we could not fully test the functionality of this endpoint since frontend does not have it. -
The implementation MuteViewSet as follows:
class MuteViewSet(viewsets.ModelViewSet):
queryset = Mute.objects.all()
serializer_class = MuteSerializer
permission_classes = [permissions.IsAuthenticated, IsFollowerOwnerOrReadOnly]
def perform_create(self, serializer):
serializer.save(muter=self.request.user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.muter != request.user:
return Response(
{"res": "You are not authorized to delete this mute."},
status=status.HTTP_403_FORBIDDEN,
)
else:
self.perform_destroy(instance)
return Response(
{"res": "Mute deleted successfully."}, status=status.HTTP_204_NO_CONTENT
)
- While doing the implementation, I worked with Mücahit and he showed me how to implement an endpoint. He also provided a tutorial for us in our Wiki.
- Unit test for previously mentioned mute endpoint as follows:
from rest_framework import status
from rest_framework.test import APITestCase, APIClient
from django.contrib.auth.models import User
from core.models import Mute
from django.urls import reverse
class MuteViewSetTest(APITestCase):
def setUp(self):
self.client = APIClient()
self.user1 = User.objects.create_user(username='user1', password='password1')
self.user2 = User.objects.create_user(username='user2', password='password2')
self.user3 = User.objects.create_user(username='user3', password='password3')
self.mute1 = Mute.objects.create(muter=self.user1, muted=self.user2)
self.create_url = reverse('mute-list') # URL to create a new mute
self.delete_url = reverse('mute-detail', args=[self.mute1.id]) # URL to delete the created mute
def test_create_mute(self):
self.client.login(username='user3', password='password3')
data = {'muted': self.user2.id}
response = self.client.post(self.create_url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Mute.objects.count(), 2)
self.client.logout()
def test_destroy_mute_by_authorized_user(self):
self.client.login(username='user1', password='password1')
response = self.client.delete(self.delete_url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertEqual(Mute.objects.count(), 0)
self.client.logout()
def test_destroy_mute_by_unauthorized_user(self):
self.client.login(username='user3', password='password3')
response = self.client.delete(self.delete_url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(Mute.objects.count(), 1)
self.client.logout()
Contribution | Footprint |
---|---|
Documented the meeting notes for mobile team's meeting 2. Important part of the mobile implementation had been shared among the team members in this particular meeting and its record had been hold in the meeting notes. | #348 |
Implemented the profile page component for the mobile. With the implementation of the profile page component, users gained the ability to see their profile page. In these pages, users' fullnames, brief info texts, their profile pages, and other information can be seen . | #349 |
-
For the challenges I and my other team mates faced, I think the biggest one was being a team. First of all I want to make it clear that we have been a very great team throughout the semester and helped each other in every way possible. However, due to not being accustomed to work together as a team, coordination sometimes was lost, efficiency was also lost too. Yet, I understood that all of these was a part of the team environment. There is no perfect team. Sometimes what we need to do is to use what we got. For me, my team, group 11 is a perfect embodiment of a real team. Everyone was ready to be a part of a work even though none of us had been inside of a team whose resposibility was to manage this kind of work.
-
I had mostly worked in the mobile part of the implementation, and the lack of experience in this field really made me process slow. I assumed I would be fine and find time to learn and implement all the things I needed to do. However, learning and putting these studies into a legit, presentable work was not that easy as I expected. This challenge was not to solve, but to understand that sufficient time must be given to specific task for especially those the implementer has little idea about. But, for this project, unfortunatelly we had not that much time. Therefore, management of learning process had quickly become messy. Thinking straight became harder and harder as time passed due to accumulated work load of newly introduced challenges.
-
In addition to having a 10 members team, having small teams that needs to be sync all the time was an issue while implementing the project. While I and other members on the mobile team were working on specific tasks, it was very important that backend team was also working on them, since testing would be fully done when backend was also inside the equation. Moreover, we had to be sync in web team because web and mobile should be as similar as possible due to consistency reasons. Therefore, we had to give tasks to specific members inside of all the teams to communicate with the other team, but in the end, every member started doing this task. This was a necessity due to accumulated task flow of the project. It might have not been a perfect example of coordination, but it was the best I had ever seen since this was my first team for developing an app.
404: Remove user context, use auth loader 405: Loader and actions for profiles. 406: Make dropdown menu functional on navbar
Create post, view post, and post edit delete This PR was created by Hasan Kerem to kickstart the Feed of our web application. We have collaboratively put effort to make it the final result that we can use. You can see the relevant discussions, screenshots and commit messages; hence all the digital footprint about the posts' evolution.
Profile Page This PR involves work done to get our profile page on the web app functional. It involves creating conditional renderings for different types of viewers (owner of the profile, someone else), adding relevant components to make it feature-fledged, using the styling from the theme to make it coherent and using fetcher forms to make it send requests to the backend.
Connections and Refinements
This PR was created to make develop
branch sync with the current develop-web
. It includes work done for refining post component, profile component; creating a navbar and user dropdown component and making them more functional alongside with other design & behavior changes.
I haven't primarily focused on documentation in this milestone as the things to complete were way bigger challenge. However I helped M. Emin to modify our login
and register
actions to comply with the new backend api.
PR Links: #440 #444 Issue Links: #439 #443
Since I have been responsible for client side application, I did not take a big role on creating server endpoints to consume.
I have created an endpoint (/v2/info
) with Hasan Kerem for searching the WikiData. This returns essential information about a given hero (defined with qid
) as a key value pairs so that we can use in web app. Here is the PR Link: #426
I was also involved in deciding the schema for various endpoints like /users
, profiles/
, /user-profile
, search/
so that we can sync backend with frontend.
The response is the following
email:string
title:string
fullname:string
picture:string
biography:string
- I have not written any unit tests, I have handled the response coming from backend to provide a better UX for the users. This includes chechking for response status, validating the schema with valibot and displaying a notification component on the web app when necessary.
The most prominent API used in frontend was the types api provided with Typescript, a superscript of Javascript. We created our application fully type-safe. Understanding general types and inferred types were quite crucial for app to reliably work
Another important 3rd party API was react-router
& react-router-typesafe
to create frontend routes in a solid and digestible manner.
We have also managed to create schema validation for some of the endpoints. For that purpose we have used valibot
.
An example schema:
const postSchema = object({
author: number(),
author_profile: any(),
bookmark_count: number(),
content: string(),
created_at: string(),
id: number(),
image_src: nullable(string()),
is_bookmarked: boolean(),
is_following: boolean(),
is_liked: boolean(),
like_count: number(),
title: string(),
qid: nullable(string()),
qtitle: nullable(string()),
updated_at: string(),
liked_by: nullable(array(string())),
});
Ümit Can Evleksiz |
---|
(REPO) Created issue templates and template configurator |
(REPO) Created our Wiki home page (landing page) and modified as we progress. i.e. add team members' bio and efforts. Created _Footer and _Sidebar pages and took care of them. Created image assets for the Wiki, and the Milestone Report. |
(DES) Created Figma team, invited team members in it, and initalized our Figma project, Designed an application logo, made design & branding decisions for the app. These are mentioned in the Mockup Screens. |
(DES) Designed 20+ ui screens, designed subpages and modals to fit the 5 user scenarios. Modified designs and provided design assets to help desktop and mobile application development. The designs can be found at our Figma document. Collaborated with Hasan Kerem and Arayici for web designs and with Emre for mobile designs. |
(DES) Helped M. Arayici refine Use Case Diagrams. Spotted a few points to improve. Reviewed Sequence Diagrams. Made minor refinements on Class Diagrams |
(DOCS) Wrote a readme file for backend & containerization with the help of Arayici. Also helped Mucahit write readme file for frontend application |
(FE) Led the frontend project, discussed several design decisions with Hasan Kerem. Decisions settled on include: Language (TS), Tooling (Vite), UI Library (Mantine), Styling Approach (Utility classes with TailwindCSS), Schema Validation (Valibot) etc. My all FE Issues |
(FE) Configured PostCSS, Tailwind and MantineUI for them to work together. An Issue Also created a type-safe router structure in the application |
(FE) Wrote custom button, inlineLink, checkbox components for the FE. |
(FE) Added typesafe-react-router and configured it in the FE. Issue |
(FE) Implemented Login and Register routes with Hasan Kerem |
(FE) Wrote actions and loaders from the routes Home, Login, and Register, Profile Loaders are the functions to be invoked whenever a route is transitioned to and the actions are the functions to be invoked whenever a non-GET (POST, PUT, PATCH, etc) request is made into some endpoint. Loaders help fetching data on each route render, and actions help respond to user form submission (search, enter login credentials etc.) |
(BE) Introduced different response codes to the backend team and regularized our error responses. This was sneaked into this PR |
(FE) Worked on post component, made it better functional and more appealing. Assigned actions to the buttons in it. |
(FE) Worked on profile page, implemented a conditional rendering logic, created forms to edit information, and a layout to make it coherent with the home page. |
(FE) Created a navbar component that includes a search dropdown, a search query, auth actions and app logo. |
(BE) Worked on the /info endpoint with Hasan Kerem. PR
|
(FE) Created a WikiWidget component to be able to use semantic information coming from /info endpoint. |
(FE) Created a component for New Post modal, created another modal for the "see who liked this post" screen. Unfortunately this is not to be seen in the deployed application due to some build failures on our CI/CD. |
(FE) Various frontend tasks include 438 #451 #452 |
- Updating UML Diagrams: This issue covers the updating process of all UML Diagrams that I have completed with Hasan Kerem Şeker and Mücahit Erdoğan Ünlü before the implementation phase. Beforehand, I was mainly responsible for creating the Use-Case UML Diagram & Search Post UML Sequence Diagram with Muhammed Emin Arayıcı.
- Dockerization & Deployment of Web Application: This issue covers the deployment process of the web application. We created separate issues for deployment of each service in our server. There are two more issues highly related to this issue: Database Service Deployment and Backend Service Deployment. All processes related to Dockerization & Deployment of our application is completed by Muhammed Emin Arayıcı and me.
-
Update Profile Endpoint: This issue covers the development process of
api/v2/profiles/
endpoint. It is important to note that this issue is highly related to previous issue about the work I have completed on same endpoint.
-
Profile Endpoint Features & Follow Endpoint Fixes: This PR covers the work done on the
/api/v2/profiles/
&/api/v2/follows/
endpoints. It is important to note that this PR follows the work done on the previous PR about/api/v2/profiles/
, thus these two PR covers all the work I have completed about these two endpoints. - Dockerize & Deploy Whole Application: This PR covers the work I have completed with Muhammed Emin Arayıcı about the whole deployment process of our application.
-
Post Endpoint Features: This PR covers the work I have completed about PATCH & DELETE HTTP Requests to
/api/v2/posts/
endpoint.
- I haven't prepared any wiki documentation for describing my contributions, however, I have prepared a README file for root directory of our repository which describes the steps of the deployment of the application for building and running the application.
I have contributed to the implementation of the 3 main endpoints which play significant role on the functionality of the backend service.
- This endpoint is used to get followed users shared posts and posts of the user herself/himself. Also by providing a POST request to this endpoint, users are able to create posts. I have contributed mainly to the part of updating & deleting a post by providing the post id.
- Following steps demonstrate an example of updating and deleting a post sequentially.
- I have created a sample post,
post_id: 19
, beforehand for testing with my user@ozankrk
which is accesible with the get command.
curl -X GET http://164.90.189.150/api/v2/posts/19/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTI5NjcwLCJpYXQiOjE3MTYwNDMyNzAsImp0aSI6IjRhNTNlZTNkZjU0YjRkOWZhM2VkYTcwNmJkZDljMmE2IiwidXNlcl9pZCI6NX0.myaRt08-TUQgYv0xHe70cOrWeokMfRixq0qM113wbTE"
- Below, you can see the response of this api call. All related information about the post itself such as the likes, profile of the author or following information and so on, is returned for possible actions can be taken by the user in the client-side.
{
"id":19,
"author_profile":{"id":5,"username":"ozankrk","email":"[email protected]","fullname":"Ozan Oytun","picture":"https://i.ibb.co/kHBtv0g/zenith.png","biography":"Interested in marvel"},
"like_count":0,
"bookmark_count":0,
"liked_by":[],
"is_liked":false,
"is_bookmarked":false,
"is_following":true,
"title":"sample post",
"content":"this is the content of the sample post",
"image_src":null,
"qid":null,
"qtitle":null,
"created_at":"2024-05-18T14:50:31.904047Z",
"updated_at":"2024-05-18T14:50:31.904114Z",
"author":5
}
- Below, you can see the command for updating this post.
curl -X PATCH http://164.90.189.150/api/v2/posts/19/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTI5NjcwLCJpYXQiOjE3MTYwNDMyNzAsImp0aSI6IjRhNTNlZTNkZjU0YjRkOWZhM2VkYTcwNmJkZDljMmE2IiwidXNlcl9pZCI6NX0.myaRt08-TUQgYv0xHe70cOrWeokMfRixq0qM113wbTE"
-d '{"content" : "this is the updated content of the sample post"}'
- Below, you can see the response of this api call. Please note that the
content
field is now updated as wished.
{
"id":19,
"author_profile":{"id":5,"username":"ozankrk","email":"[email protected]","fullname":"Ozan Oytun","picture":"https://i.ibb.co/kHBtv0g/zenith.png","biography":"Interested in marvel"},
"like_count":0,
"bookmark_count":0,
"liked_by":[],
"is_liked":false,
"is_bookmarked":false,
"is_following":true,
"title":"sample post",
"content":"this is the updated content of the sample post",
"image_src":null,
"qid":null,
"qtitle":null,
"created_at":"2024-05-18T14:50:31.904047Z",
"updated_at":"2024-05-18T14:50:31.904114Z",
"author":5
}
- Below, you can see the command for deleting this post.
curl -X DELETE http://164.90.189.150/api/v2/posts/19/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTI5NjcwLCJpYXQiOjE3MTYwNDMyNzAsImp0aSI6IjRhNTNlZTNkZjU0YjRkOWZhM2VkYTcwNmJkZDljMmE2IiwidXNlcl9pZCI6NX0.myaRt08-TUQgYv0xHe70cOrWeokMfRixq0qM113wbTE"
-
The response of this api call is a successful deletion message with HTTP Code 204. If this api call is made with another user's token, which is not authorized for my user, response is a simple not authorized message with HTTP Code 403.
-
I am well aware of the fact that this is not the most secure way demonstrating the execution :), especially providing the token of my user. However, this is best way of demonstrating the workflow of the endpoint.
- I have created all parts of this endpoint with the help of Ceydanur Şen. A profile for user is created at the moment of registration of a user. I will demonstrate the PATCH request to update any field of a my user's profile.
- Below, you can see the command for getting the user, with
user_id: 5
.
curl -X GET http://164.90.189.150/api/v2/profiles/5/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTI5NjcwLCJpYXQiOjE3MTYwNDMyNzAsImp0aSI6IjRhNTNlZTNkZjU0YjRkOWZhM2VkYTcwNmJkZDljMmE2IiwidXNlcl9pZCI6NX0.myaRt08-TUQgYv0xHe70cOrWeokMfRixq0qM113wbTE"
- Below, you can see the response of this api call. All user related information in the profile page is returned since all of the returned values are, at least as designed, used in the frontend/mobile side for displaying in the profile page. Also, please note that all users have their
profile_id
equal to theiruser_id
.
{
"id":5,
"is_following":true,
"posts":[{"id":11,"username":"ozankrk","user_id":"5","like_count":0,"bookmark_count":0,"liked_by":[],"is_liked":false,"is_bookmarked":false,"is_following":true,"title":"The death of an era","content":"Here is why you should not rely on a single ... The most comprehensive approach","image_src":"https://static.wikia.nocookie.net/marveldatabase/images/e/e1/The_Marvel_Universe.png/revision/latest?cb=20110513164401","qid":null,"qtitle":null,"created_at":"2024-05-17T07:13:57.443922Z","updated_at":"2024-05-17T07:13:57.443965Z"},{"id":13,"username":"ozankrk","user_id":"5","like_count":1,"bookmark_count":1,"liked_by":["ozankrk"],"is_liked":true,"is_bookmarked":true,"is_following":true,"title":"Hawkeye","content":"Good archer","image_src":"","qid":"Q19095","qtitle":"Hawkeye","created_at":"2024-05-17T08:06:08.511891Z","updated_at":"2024-05-17T08:06:08.511941Z"},{"id":15,"username":"ozankrk","user_id":"5","like_count":2,"bookmark_count":1,"liked_by":["ozankrk","Tatü"],"is_liked":true,"is_bookmarked":true,"is_following":true,"title":"The Genius Behind The Armor","content":"Let's chat about Iron Man! Tony Stark, the genius billionaire playboy philanthropist, is behind the iconic suit. His tech innovations and battles are legendary. What's your favorite Iron Man moment or suit?","image_src":"https://images.unsplash.com/photo-1635863138275-d9b33299680b?q=80&w=3731&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D","qid":"Q180704","qtitle":"Iron Man","created_at":"2024-05-17T12:05:10.820919Z","updated_at":"2024-05-17T12:05:10.820974Z"},{"id":19,"username":"ozankrk","user_id":"5","like_count":0,"bookmark_count":0,"liked_by":[],"is_liked":false,"is_bookmarked":false,"is_following":true,"title":"sample post","content":"this is the content of the sample post","image_src":null,"qid":null,"qtitle":null,"created_at":"2024-05-18T14:50:31.904047Z","updated_at":"2024-05-18T14:50:31.904114Z"}],
"followers":["ozankrk","memin41"],
"followings":["emre","hyildirim","ozankrk","memin41","hyildirim2","johnnyS","umit","jackk","A"],
"follower_count":2,
"following_count":9,
"post_count":4,
"picture":"https://i.ibb.co/kHBtv0g/zenith.png",
"biography":"Interested in marvel",
"owner":5
}
- Below, you can see the command for updating the user profile. The biography field is updated in this sample call.
curl -X PATCH http://164.90.189.150/api/v2/profiles/5/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTI5NjcwLCJpYXQiOjE3MTYwNDMyNzAsImp0aSI6IjRhNTNlZTNkZjU0YjRkOWZhM2VkYTcwNmJkZDljMmE2IiwidXNlcl9pZCI6NX0.myaRt08-TUQgYv0xHe70cOrWeokMfRixq0qM113wbTE" \
-d '{"biography" : "I am currently interested in DC"}'
- Below, you can see the response of this api call. Please note that biography field is now updated as wished.
{
"id":5,
"is_following":true,
"posts":[{"id":11,"username":"ozankrk","user_id":"5","like_count":0,"bookmark_count":0,"liked_by":[],"is_liked":false,"is_bookmarked":false,"is_following":true,"title":"The death of an era","content":"Here is why you should not rely on a single ... The most comprehensive approach","image_src":"https://static.wikia.nocookie.net/marveldatabase/images/e/e1/The_Marvel_Universe.png/revision/latest?cb=20110513164401","qid":null,"qtitle":null,"created_at":"2024-05-17T07:13:57.443922Z","updated_at":"2024-05-17T07:13:57.443965Z"},{"id":13,"username":"ozankrk","user_id":"5","like_count":1,"bookmark_count":1,"liked_by":["ozankrk"],"is_liked":true,"is_bookmarked":true,"is_following":true,"title":"Hawkeye","content":"Good archer","image_src":"","qid":"Q19095","qtitle":"Hawkeye","created_at":"2024-05-17T08:06:08.511891Z","updated_at":"2024-05-17T08:06:08.511941Z"},{"id":15,"username":"ozankrk","user_id":"5","like_count":2,"bookmark_count":1,"liked_by":["ozankrk","Tatü"],"is_liked":true,"is_bookmarked":true,"is_following":true,"title":"The Genius Behind The Armor","content":"Let's chat about Iron Man! Tony Stark, the genius billionaire playboy philanthropist, is behind the iconic suit. His tech innovations and battles are legendary. What's your favorite Iron Man moment or suit?","image_src":"https://images.unsplash.com/photo-1635863138275-d9b33299680b?q=80&w=3731&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D","qid":"Q180704","qtitle":"Iron Man","created_at":"2024-05-17T12:05:10.820919Z","updated_at":"2024-05-17T12:05:10.820974Z"},{"id":19,"username":"ozankrk","user_id":"5","like_count":0,"bookmark_count":0,"liked_by":[],"is_liked":false,"is_bookmarked":false,"is_following":true,"title":"sample post","content":"this is the content of the sample post","image_src":null,"qid":null,"qtitle":null,"created_at":"2024-05-18T14:50:31.904047Z","updated_at":"2024-05-18T14:50:31.904114Z"}],
"followers":["ozankrk","memin41"],
"followings":["emre","hyildirim","ozankrk","memin41","hyildirim2","johnnyS","umit","jackk","A"],
"follower_count":2,
"following_count":9,
"post_count":4,
"picture":"https://i.ibb.co/kHBtv0g/zenith.png",
"biography":"I am currently interested in DC",
"owner":5
}
- I have updated this endpoint so that all HTTP requests can be made by providing the
user_id
in the URL so that front-end and mobile side can use this endpoint inside posts and profiles to control follow operations. - Below, you can see an example of getting an information whether my user,
@ozankrk
, is following the user withuser_id: 3
.
curl -X GET http://164.90.189.150/api/v2/follows/3/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTI5NjcwLCJpYXQiOjE3MTYwNDMyNzAsImp0aSI6IjRhNTNlZTNkZjU0YjRkOWZhM2VkYTcwNmJkZDljMmE2IiwidXNlcl9pZCI6NX0.myaRt08-TUQgYv0xHe70cOrWeokMfRixq0qM113wbTE"
- Below, you can see the response for this call.
id
field shows the id of follow object.follower
andfollowing
fields shows the ids of the follower user and the user that he/she follows.
{
"id":1,
"follower_username":"ozankrk",
"following_username":"emre",
"created_at":"2024-05-17T06:54:49.574006Z",
"follower":5,
"following":3
}
- Other HTTP requests can be done just as above by just modifying the request parameter of
$curl
command. Please don't forget the changing theuser_id
in the URL for necessary action related to specific user.
- Here, you can find the unit test I have written for testing the endpoint for posts. Please note that this test is not pushed to the repository, since I have used this test only on my local development environment.
- The test file below should be put into /backend/core/tests folder for testing with name
test_posts.py
(recommended) and in order to run all test, simply run the command below.
cd bounswe2024group11/backend
python manage.py test
- Code for this unit test is attached below.
from rest_framework.test import APITestCase, APIClient
from rest_framework import status
from django.urls import reverse
from django.contrib.auth.models import User
from core.models import Post
class PostTests(APITestCase):
def setUp(self):
self.client = APIClient()
self.user = User.objects.create_user(username="testuser_post", password="testpassword_post")
self.client.force_authenticate(user=self.user)
self.post = Post.objects.create(author=self.user, title="Test Post", content="Test Content")
def test_get_post(self):
response = self.client.get(reverse('post-detail', kwargs={"pk": self.post.pk}))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["title"], self.post.title)
self.assertEqual(response.data["content"], self.post.content)
self.assertEqual(response.data["author"], self.user.id)
def test_update_post(self):
data = {"content": "Updated Content"}
response = self.client.patch(reverse('post-detail', kwargs={"pk": self.post.pk}), data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["content"], data["content"])
def test_delete_post(self):
response = self.client.delete(reverse('post-detail', kwargs={"pk": self.post.pk}))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
- I have created a reverse-proxy structure in our deployment server so that our endpoints can be accessible without providing a port number. NGINX configuration is added in front of the whole service structure so that calls with starting with
/api
is directed to backend service whereas clients are directed to front-end service otherwise. You can access to the issue and the pull request of this contribution here. - CORS related errors were constantly faced at the frontend development side. I have made necessary configurations for CORS allowed hosts in the
config/settings.py
file at the/backend
directory with the help of Muhammed Emin Arayıcı. You can access to the issue and the pull request of this contribution here.
- Backend related development was an area that I have been mostly avoiding of before this course, since I was not interested in this area of Computer Engineering. I was going through an hardship of creating views since it was kind of hard for me to understand the Django Framework's structure caused by my lack of experience. By the time, with the help of my teammates and documentations & forums about the framework, I got used to write code for backend side.
- Docker is an application makes running remote servers super efficiently, however, it hides most of the processes it runs behind the scenes due to transparency policy of the application. Thus, errors we have faced with Muhammed Emin Arayıcı during the deployment process took our time to overcome. We have searched through web and got the help of LLMs such as ChatGPT, also we have watched lots of tutorials, to understand the structure of Docker which leaded us to solutions of our problems in the deployment.
- Another challenge I have faced was the communication issues with my teammates which I was not expecting to face. I think, most of team members tried to make contributions in order to finish our milestone completely due to time pressure the team faced. However, at some points, we couldn't manage to populate team's efforts, at the backend side, in a cumulative manner at some point which made us lose relatively large amount of time.
- Lastly, the fact that this course's grades are given individually makes people to focus on their contributions only, sometimes, instead of putting a team work which leads to inefficient situations in case of team working.
- Personally, I want to thank to my teammate Muhammed Emin Arayıcı who helped me overcoming most of the challenges I have faced.
- Identify User Requirements #69:
- This issue covers all details in user requirements. In this issue, I have identified the user requirements by reading the project description, assessing the answers which we have asked in customer meeting and following the requirement specification practices.
- Class Diagrams #149:
- This issue covers the improvements to a prototype class diagram using the requirements. In this issue, Hasan Kerem and I assessed the first version of the class diagram and identified the missing details. We come up with some solutions to Search and Post and drew the improved class diagram using the mermaid library in GitHub Markdown.
- Build the Mobile App #333:
- This issue covers the building and deployment of the mobile application. The implemented mobile app had been tested on emulators before releases. Taking the build requires testing of the application using real mobile phones and solving building related problems. With Muhammed Emin Arayıcı, we have managed to solve all bugs related to production build and prepare our app to the release.
- feat(mobile): added token to user context and api calls #379:
- This pull request covers the modifications of all API calls and session control. After the backend system had changed, the HTTP requests and session control mechanisms had to change. In this pull request, the user context which stores session related user data is modified and the access token based system is added in the HTTP request library that we implemented. This token is stored in the context.
- feat(backend): add login endpoint with swagger, bruno and unit tests #407:
- This pull request covers all details of developing the login enpoint with implementation, testing and documentation. I have implemented the login endpoint which is described below in the API description part. I also have added the unit tests and swagger documentations of that endpoint in the same pull request.
- feat(mobile): connect to backend #431:
- This pull request covers all details in implementing new API call functions and editing the old calls. Our backend has been changed due to some implementation choices and eases of the new solution. This change causes new problems for mobile application in terms of connecting these two parts. Muhammed Emin Arayıcı and Yunus Kağan Aydın, two participants of the backend team, helped me to figure out the new API descriptions and solve the new issues.
You can find the documentations I have written in the wiki page across the project. These researches helped us to figure out the nature of semantic browsing and WikiData SPARQL query mechanism. These researches also provides a good and compact information about the searching mechanism of this project. The team then used the general information about semantic search and examples provided in SPARQL documentation to implement the semantic searching of our application. I have contributed to these documents with Hasan Kerem and Ümit Can.
- Semantic Browsers documentation
- SPARQL documentation
- I have implemented the
login/
API endpoint of our application. This endpoint gets username and password and handles the authorization process. Thanks to Mücahit, I have learned how to implement an API function. He also helped and reviewed me during this implementation process. - The API creates the session and sends user data and access tokens to the frontend side. Returns refresh token to refresh the access when the token is expired. Returns access token
- The method of the
login/
endpoint isPOST
. Other types of methods are not accepted in this endpoint. - This request accepts two body parameters:
username
andpassword
. These parameter should not be null. - The example usage is given as a bash command below:
curl -X POST http://164.90.189.150/api/v2/login/ \
-H 'Content-Type: application/json' \
-d '{ "username": "emre", "password": "emre"}'
- This HTTP request handles the body and returns 3 different responses:
- Response code
200
- This response refers to a successful login operation and returns three fields as a result of this login operation. The response of this example successful result is below:
{ "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcxNjY2ODUxOSwiaWF0IjoxNzE2MDYzNzE5LCJqdGkiOiJhMWYyMjNlY2U0NWY0YTJiYmI4YmVjYThjYTI2ZjEzZCIsInVzZXJfaWQiOjN9.F32U9JYp3LXAn6gPSOLpZHcrt0Ww9pO1xUWf0ske7nk", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTUwMTE5LCJpYXQiOjE3MTYwNjM3MTksImp0aSI6IjAwYjU4YmZmOGVmYTQyNGQ5MWI4Y2U3ZDk0NDhiMTFhIiwidXNlcl9pZCI6M30.KRE7j4UqkfDlt87kahSygj6tjcc0PBIFAQwNdZ00RoI", "user": { "id":3, "username": "emre", "email": "[email protected]", "fullname": "Emre Kilic" } }
- Response code
400
- This response refers to a bad request where the request body has some missing details. It returns a single error field corresponding to the error message. A response of an example bad request where the username or password has not been given as a body is below:
{ "error": "Please provide both username and password" }
- Response code
401
- This response refers to an invalid credentials. This response is generated when a login operation is tried with a non existing username or wrong password. It returns a single error field corresponding to the error message. A response of an example of an invalid request is below:
{ "error": "Invalid credentials" }
- Response code
- The documentation of this API endpoint is documented using swagger. It is part of the deployment and can be reached through the swagger page of our website. The code snippet of the swagger documentation is below.
login_swagger = {
"request_body": openapi.Schema(
type=openapi.TYPE_OBJECT,
required=["username", "password"],
properties={
"username": openapi.Schema(
type=openapi.TYPE_STRING, description="The username of the user."
),
"password": openapi.Schema(
type=openapi.TYPE_STRING, description="The password of the user."
),
},
),
"responses": {
200: openapi.Response(
description="Login successful. Returns the user details and tokens.",
schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
"refresh": openapi.Schema(
type=openapi.TYPE_STRING,
description="The refresh token for the user.",
),
"token": openapi.Schema(
type=openapi.TYPE_STRING,
description="The access token for the user.",
),
"user": openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
"id": openapi.Schema(type=openapi.TYPE_INTEGER),
"username": openapi.Schema(type=openapi.TYPE_STRING),
"email": openapi.Schema(type=openapi.TYPE_STRING),
"first_name": openapi.Schema(type=openapi.TYPE_STRING),
"last_name": openapi.Schema(type=openapi.TYPE_STRING),
},
),
},
),
),
400: "Please provide both username and password.",
401: "Invalid credentials.",
},
}
- Within the implementation of the
login/
API endpoint, the unit test related to this operation is also implemented. The test script is added to the repository intest_login.py
. You can run the test using this script after cloning the repository.
cd bounswe2024group11/backend
python manage.py test
- The unit test is implemented using Django Rest Framework
APITestCase
class. In the testing process, a test user is created with the code snippet below.
def setUp(self):
self.url = reverse("login")
self.username = "testuser"
self.password = "testpassword"
self.user = User.objects.create_user(
username=self.username, password=self.password
)
- With this test user, all three possible responses are tested with the code snippets below.
def test_login_success(self):
data = {"username": self.username, "password": self.password}
response = self.client.post(self.url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn("refresh", response.data)
self.assertIn("token", response.data)
self.assertIn("user", response.data)
self.assertEqual(response.data["user"]["username"], self.username)
def test_login_missing_credentials(self):
data = {"username": self.username}
response = self.client.post(self.url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data["error"], "Please provide both username and password"
)
def test_login_invalid_credentials(self):
data = {"username": self.username, "password": "wrongpassword"}
response = self.client.post(self.url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
self.assertEqual(response.data["error"], "Invalid credentials")
- Here you can find my milestone 3 contributions as a table corresponding to its digital footprint.
Contribution | Footprint |
---|---|
Implemented the screen where users create a post in mobile. This screen can be reached with a button in feed screen. The navigation of this screen is also added to the system by editing the navigation container in home screen. | #355 |
Edited the request library where other components creates HTTP requests. New library functions are added for every HTTP request method that is used throughout the implementation. | #368 |
Implemented a suggestion feature which is used in create post and search. Two main functionalities are with this contribution. A component which renders the suggestions and the HTTP request to handle the information and communication. | #371 |
Modified user context which is used to store the user data and used for session control. After the modifications and improvements in the backend, the API access tokens are added to this user context and login API connection is modified according to support the new features. | #379 |
Implemented the login API endpoint. After discarding the old authentication system in milestone 2, the login API endpoint must be written from scratch with new system. In this contribution, all the details related to login operation is added. Unit tests, API swagger documentations and HTTP responses are implemented. | #407 |
- The biggest challenge of this project was the lack of experience. I have never been part of a software development team. It was challenging to orientate in the group and communicate each other. At first, I tried to be active in every task to ensure that everything works fine. This was good in the first place because of the low workloads of the tasks. It helped me to learn every aspect of the process of designing a software. After the tasks became overwhelming and required some output as a group, We had to find a nice way of dividing the tasks and catch the deadlines. Besides the team experience, I also have never developed a software app from scratch. We had to figure out the way of designing, implementing, testing and deploying the app. I think we have managed to work as a team and finished the project.
- Developing mobile application was a challenging task, too. I have never developed a React Native mobile application. And before that, I have never written javascript. The challenge was learning how the things work in a language which is quite high level. Then I have learned the main functionalities in React API and after that I have managed to learn the React Native.
- Taking production builds was another challenging task. We used Expo tool thinking our DevOps part for the mobile would be easier. But Expo requires that the builds should be taken in the remote server but local system. Using free accounts for server usage was time-consuming and caused some unnecessary procedures. In every build, I had to solve some bugs related to the differences between development server and production builds. After adding necessary Android flags to solve and suppress the errors and took the working build.
- There are some challenges in UI libraries in React Native. Some libraries are still under development and have inner problems. So I had to figure out whether the errors come from us or from the library. Additionaly, some features are not exist in UI libraries so I had to implement them on our own. The suggestion feature is implemented from scratch.
- Connecting to backend was a difficult task. As it is understood easily from the history of pull requests, I had to revise and modify the HTTP requests again and again. Old system required FormData format in HTTP request body and new system required traditional JSON string. I had to change and modify headers and other procedures in order to establish a working connection to backend.
- feature(web): implement create post, view post, and post edit delete dropdown ui
- feature(web): implement profile ui
- feat(backend): expose wiki data info endpoint
- Semantic Search and its issue
- Implemented Wiki Info endpoint (
/v2/info
) with Mücahit Erdoğan Ünlü and Ümit Can Evleksiz. This API allows us to query wikidata using a keyword and return the result to the frontend.
- Implemented tests for Wiki Info view with Mücahit Erdoğan Ünlü and Ümit Can Evleksiz. This test has three cases.
- The first case is querying with a valid qid and this must return valid results having fileds like Inception, Gender, Birth Name', Place of Birth, Image, Description, Label.
- The second case is querying with an invalid qid and this must return an error message 'QID should start with "Q".' and status code 400.
- The third case is querying without a qid and this must return an error message 'Parameter 'qid" is required.' and status code 400.
Task |
---|
Created five user scenarios(Scenario 1 Scenario 2 Scenario 3 Scenario 4 Scenario 5) with Ceydanur Şen |
Read React Router documentation to create Example Routes |
Created the initial version class diagrams with Emre Kılıç and Mücahit Erdoğan Ünlü. |
Created the initial Sequence Diagrams which can be seen from the history tab of the sequence diagrams. It is the oldest version called Initial Sequence diagram draft |
Bootstrapped the Frontend Application |
Created Example Routes |
Updated the Project Plan to include detailed subtasks of frontend, backend, and mobile teams with Muhammet Emin Çiftçi and Ozan Karakaya |
Updated the Class Diagram to add missing methods and moved every database methods into their respective controller class with Mücahit Erdoğan Ünlü and Ozan Karakaya |
Updated the Sequence Diagram to reflect changes of the class diagram and added search sequence diagram with Mücahit Erdoğan Ünlü and Ozan Karakaya |
Created develop-web branch to separate production branch from the development branch which we push new features. The respective issue can be seen here |
Determined subroutes and query parameters with Ümit Can Evleksiz |
Created the Login Page and Ümit Can Evleksiz helped to do styling |
Designed Initial Homepage and Ümit Can Evleksiz helped to do styling |
Implemented custom keyboard focus styling with Ümit Can Evleksiz |
Replaced Dialog with Toast Notification component. Issue, Pr |
Update project structure in readme. Issue |
Created the Initial Post Component. Issue, Pr |
Created Initial Profile Page UI. Issue, Pr1, Pr2 |
Created Initial Post Feed UI. Issue, Pr |
Created Modal UI For Create Post. Issue, Pr |
Implemented WikiData Search Endpoint with Mücahit Erdoğan Ünlü and Ümit Can Evleksiz. Issue, Pr |
- I could not connect the web application to the back end. This was due many factors. We had a working back end at just night before the demo which was not enough to handle the errors like connecting wiki data search suggestions and wiki data search. However mobile team was able to connect to the back end because they had a more manual approach instead of the web team's approach which tried to utilize the power of libraries and best practices which led to us being more obsessed with complying to best practices instead of achieving the tasks. The web team could have implement the things in more manual fashion instead of relying functionalities provided by libraries which made harder and longer to solve errors.
- The styling using class variance authority was problematic for me. I could not overwrite the classes created by Ümit Can so I created my classes duplicating his classes and just changing few things. After consulting him I deleted unnecessary classes and used divs to encapsulate and style the element which has a styling to be overwritten.
- I could not run back end on my device. Mücahit helped me while creating the virtual environment and fixing errors while installing dependencies.
- Curl
curl -X 'GET' \
'http://localhost:8000/api/v2/info/?qid=Q79037' \
-H 'accept: application/json' \
-H 'X-CSRFToken: Eh9GlB4uFzMjjk1Yn5Xc6gK7Zre16JX0O2q3bUMUCEc11FcwiD5kkuP7f7NQbOTf'
- Request Url
http://localhost:8000/api/v2/info/?qid=Q79037
Replace Q79037
with the desired valid Qid to execute it.
{
"keyword": "Q79037",
"results": [
{
"Inception": "1962-08-01T00:00:00Z",
"Gender": "male",
"Birth Name": "Peter Benjamin Parker",
"Place of Birth": "Queens",
"Image": "Unknown",
"Description": "fictional character in Marvel Comics",
"Label": "Spider-Man"
}
]
}
from django.urls import reverse
from rest_framework.test import APITestCase
class WikiInfoViewTestCase(APITestCase):
def test_wiki_info_view_with_valid_qid(self):
# Sending a GET request to the endpoint with a valid QID
response = self.client.get(reverse('info'), {'qid': 'Q2695156'})
# Asserting that the response status code is 200
self.assertEqual(response.status_code, 200)
# Asserting that the response contains the keyword 'results'
self.assertIn('results', response.data)
# Asserting that the response contains the keyword 'keyword' with the correct QID
self.assertEqual(response.data['keyword'], 'Q2695156')
# Asserting that the response contains data for the 'results' key
results = response.data['results']
self.assertIsInstance(results, list)
self.assertGreater(len(results), 0) # Asserting that results list is not empty
# Asserting the structure of each result item
for result in results:
self.assertIn('Inception', result)
self.assertIn('Gender', result)
self.assertIn('Birth Name', result)
self.assertIn('Place of Birth', result)
self.assertIn('Image', result)
self.assertIn('Description', result)
self.assertIn('Label', result)
def test_wiki_info_view_with_invalid_qid(self):
# Sending a GET request to the endpoint with an invalid QID
response = self.client.get(reverse('info'), {'qid': 'invalid_qid'})
# Asserting that the response status code is 404
self.assertEqual(response.status_code, 400)
# Asserting that the response contains the keyword 'res' with the error message
self.assertIn('res', response.data)
self.assertEqual(response.data['res'], 'QID should start with "Q".')
def test_wiki_info_view_without_qid(self):
# Sending a GET request to the endpoint without a QID
response = self.client.get(reverse('info'))
# Asserting that the response status code is 400
self.assertEqual(response.status_code, 400)
# Asserting that the response contains the keyword 'res' with the error message
self.assertIn('res', response.data)
self.assertEqual(response.data['res'], 'Parameter "qid" is required.')
- Create an endpoint for the profile page
- Implement 2 Wikidata and a Search API endpoints
- Create a Token Validation Mechanism for Registered User's Actions
- feat(backend): add profile endpoint
- feat: add new implementation for wikidata and search endpoints
- feat(backend): add unique profiles for each user
- Implemented an endpoint for the profile page with Ozan Oytun Karakaya. While registering, user creates a profile page having features: biography, profile picture and username. Also each user can only have one unique profile page. User can update the fields totally or partialy afterwards.
curl -X PATCH http://164.90.189.150/api/v2/profiles/5/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_access_token" \
-d '{"profile_picture": "URL for the image"}' \
curl -X GET http://164.90.189.150/api/v2/profiles/5/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTI5NjcwLCJpYXQiOjE3MTYwNDMyNzAsImp0aSI6IjRhNTNlZTNkZjU0YjRkOWZhM2VkYTcwNmJkZDljMmE2IiwidXNlcl9pZCI6NX0.myaRt08-TUQgYv0xHe70cOrWeokMfRixq0qM113wbTE"
curl -X DELETE http://164.90.189.150/api/v2/profiles/5/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer access_token" \
- Implemented wikidata search queries used to implement WikidataSuggestionsView enpoint with Mücahit Erdoğan Ünlü. After chosing filtering options such as born in and occupation, related wikidata entities are returned using this endpoint.
curl -X GET "http://164.90.189.150/api/v2/suggestions/?keyword= new york"
-H "Content-Type: application/json" \
[
{
"qid": "Q60",
"label": "New York City",
"description": "most populous city in the United States"
},
{
"qid": "Q1384",
"label": "New York",
"description": "state of the United States of America"
},
...
]
- I did not implement a unit test for the parts I completed due to lack of time. However, I learned how to write unit tests from the documentation in our wiki throughly.
- I searched and learned token validation mechanisms for the endpoints implemented.
- Decided on the query logic and the filtering options for the search functionality.
Sample Semantic SPARQL Query:
SELECT DISTINCT ?item ?itemLabel (SUM(?sitelink) AS ?sitelinks)
WHERE {
?item wdt:P31 wd:Q1114461;
wdt:P106 wd:%s;
rdfs:label ?itemLabel.
?item wikibase:sitelinks ?sitelink.
FILTER(LANG(?itemLabel) ="en").
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?item ?itemLabel
ORDER BY DESC(?sitelinks)
I have implemented the semantic search queries for the various catagories we decided. Above, it can be seen a sample semantic sparql query implemented for "occupation" catagory.
- Building API as a fundemental aspect of the backend development, I tried to learn RESTful principles, request/response handling, authentication, and serialization/deserialization concepts in a short amount of time. Since having no prior experience, learning and implementing these concepts were challenging. With the help of online tutorials and documentations, I implemented various functionalities for our backend side.
- I had hard time to solve the error handling part for the endpoint I implemented. At the beginning, I could not get the logic behind the error and spent a lot of time to solve the problem. I solved the issue with the help of my team.
- Wikidata Suggestions and Post Search Endpoints Issue
- Like Bookmark Counters on PostSerializer
- Write Tutorials on Model, Serializer, and Views. The importance is explained.
- Wikidata Suggestions and Post Search Endpoints PR and commit
- Like Bookmark Counters on PostSerializer
- add is_follower field to postsearchserailizer and profileserializer
Wiki documentation Tutorial on Django Models Tutorial on Django REST Serializers Tutorial on How to Implement A Django Rest API Tutorial on How to Write and Use Swagger API Tutorial to Write Unit Tests For Django REST API endpoints
Third Party Wikidata Search API In order to get the QID's of the user's search keys, I used
url = f"https://www.wikidata.org/w/api.php?action=wbsearchentities&search={keyword}&language=en&format=json"
Endpoint: https://www.wikidata.org/w/api.php Description: The Wikidata Search API allows users to search for Wikidata entities by a keyword. Parameters: action: Specifies the action to be performed. For search, it is wbsearchentities. search: The keyword to search for. language: The language for the search results (e.g., en for English). format: The format of the response (e.g., json). Sample API Call
https://www.wikidata.org/w/api.php?action=wbsearchentities&search=python&language=en&format=json
Sample API Response
{
"searchinfo": {
"search": "python"
},
"search": [
{
"id": "Q28865",
"title": "Q28865",
"pageid": 32213,
"display": {
"label": {
"value": "Python",
"language": "en"
},
"description": {
"value": "general-purpose programming language",
"language": "en"
}
},
"repository": "wikidata",
"url": "//www.wikidata.org/wiki/Q28865",
"concepturi": "http://www.wikidata.org/entity/Q28865",
"label": "Python",
"description": "general-purpose programming language",
"match": {
"type": "label",
"language": "en",
"text": "Python"
}
},
{
"id": "Q271218",
"title": "Q271218",
"pageid": 262489,
"display": {
"label": {
"value": "Python",
"language": "en"
},
"description": {
"value": "genus of reptiles",
"language": "en"
}
},
"repository": "wikidata",
"url": "//www.wikidata.org/wiki/Q271218",
"concepturi": "http://www.wikidata.org/entity/Q271218",
"label": "Python",
"description": "genus of reptiles",
"match": {
"type": "label",
"language": "en",
"text": "Python"
}
},
Wikidata Suggestions API
Endpoint:
http://164.90.189.150:8000/api/v2/suggestions/
keyword: The query parameter that is the keyword to search for. Method: GET Description: This API takes a keyword from the user and uses Third Party Wikidata API to get their QID's labels and descriptions so that a user can select what he means by a specific word. Then we can uses that QID to make a semantic search on Wikidata.
Note: This could have used on frontend directly to make it more efficient; however, to have greater control over the query it is implemented on backend.
- The view checks for the presence of the "keyword" query parameter, makes an API call to Wikidata, and processes the response to return a simplified list of search results.
- Constructs the API URL using the provided keyword.
- Sends a GET request to the Wikidata API.
- If the response status code is 200, it processes the JSON response to extract the qid, label, and description fields from each search result and returns them in a simplified format.
- If the status code is not 200, it returns an error response with the appropriate status code.
- If an exception occurs, it returns a 500 INTERNAL SERVER ERROR response.
Sample API Call
http://164.90.189.150:8000/api/v2/suggestions/?keyword=python
Sample Response
[
{
"qid": "Q28865",
"label": "Python",
"description": "general-purpose programming language"
},
{
"qid": "Q271218",
"label": "Python",
"description": "genus of reptiles"
},
{
"qid": "Q15721",
"label": "Python",
"description": "earth-dragon of Delphi"
},
{
"qid": "Q599384",
"label": "CPython",
"description": "Python reference implementation"
},
{
"qid": "Q15728",
"label": "Python",
"description": "1978 air-to-air missile family by RAFAEL"
},
{
"qid": "Q4363952",
"label": "Python",
"description": "ancient peastan greek vase-painter of red-figure style"
},
{
"qid": "Q1249144",
"label": "Peithon",
"description": "Ancient Macedonian general"
}
]
Sample API Call 2
http://164.90.189.150:8000/api/v2/suggestions/
Sample API Response
{
"res": "Keyword parameter \"keyword\" is required."
}
Post Search API Endpoint:
http://164.90.189.150:8000/api/v2/search/
Description: It has 6 categories that a user must select one of them in the query parameter. According to the category, and the QID that is taken from the suggestions
API call, a semantic Wikidata SPARQL query is run.
Method: GET
- The code retrieves qid and category from the request query parameters.
- Returns a 400 BAD REQUEST response if either qid or category is missing.
- Based on the category, calls the corresponding helper function to fetch data that are related to the category from Wikidata.
- Extracts QIDs from the response data.
- When a GET method is called, it filters the Posts that have one of these QIDs in their tags.
- Serializes the filtered Post list queryset and returns the response.
- Returns a 500 INTERNAL SERVER ERROR response if any exception occurs.
Sample Semantic SPARQL Query:
SELECT DISTINCT ?item ?itemLabel ?itemDescription ?sitelinks ?placeOfBirthLabel
WHERE {
?item wdt:P31 wd:Q1114461;
wdt:P19/wdt:P131* wd:%s;
wikibase:sitelinks ?sitelinks.
OPTIONAL{
?item wdt:P19 ?placeOfBirth.
?placeOfBirth rdfs:label ?placeOfBirthLabel.
FILTER(LANG(?placeOfBirthLabel) ="en").
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
ORDER BY DESC(?sitelinks)
Sample API Call
http://164.90.189.150:8000/api/v2/search/?category=occupation&qid=Q205375
Q205375 is the QID of the occupation inventor
that is selected by user with the help of Wikidata API.
Sample Response
[
{
"id": 5,
"username": "memin41",
"user_id": "6",
"like_count": 3,
"bookmark_count": 1,
"liked_by": [
"memin41",
"ozankrk",
"Tatü"
],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "My Favorite Spider-Man Story Arc",
"content": "Just finished reading \"The Amazing Spider-Man: Birth of Venom\" and it was incredible! The origin of Venom is so well done, and the black suit saga is a must-read for any Spidey fan. Highly recommend it!",
"image_src": "https://www.artmajeur.com/medias/standard/k/o/konstantin1/artwork/17051995_f1a1bdec-1101-445e-b9b9-cb1f195c6981.jpg",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-17T06:51:49.392587Z",
"updated_at": "2024-05-17T06:51:49.392650Z"
},
{
"id": 15,
"username": "ozankrk",
"user_id": "5",
"like_count": 2,
"bookmark_count": 1,
"liked_by": [
"ozankrk",
"Tatü"
],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "The Genius Behind The Armor",
"content": "Let's chat about Iron Man! Tony Stark, the genius billionaire playboy philanthropist, is behind the iconic suit. His tech innovations and battles are legendary. What's your favorite Iron Man moment or suit?",
"image_src": "https://images.unsplash.com/photo-1635863138275-d9b33299680b?q=80&w=3731&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"qid": "Q180704",
"qtitle": "Iron Man",
"created_at": "2024-05-17T12:05:10.820919Z",
"updated_at": "2024-05-17T12:05:10.820974Z"
},
]
Both posts about Iron Man and Spider-Man are returned because they are both inventors according to Wikidata. Sample API Call 2
http://164.90.189.150:8000/api/v2/search/?category=born%20in&qid=Q1408
Q1408 is the QID of the New Jersey State. Sample API Response 2
[
{
"id": 7,
"username": "johnnyS",
"user_id": "8",
"like_count": 1,
"bookmark_count": 1,
"liked_by": [
"aa"
],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "Batman superior",
"content": "Just rewatched The Dark Knight and I'm blown away all over again! Batman is the ultimate symbol of resilience and justice. From his high-tech gadgets to his unwavering moral code, he proves you don't need superpowers to be a hero. Gotham's protector reminds us that anyone can make a difference. Who's your favorite Batman actor?",
"image_src": "https://images.unsplash.com/photo-1509347528160-9a9e33742cdb?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"qid": "Q2695156",
"qtitle": "Batman",
"created_at": "2024-05-17T07:04:45.543620Z",
"updated_at": "2024-05-17T11:53:25.213652Z"
},
{
"id": 14,
"username": "emre",
"user_id": "3",
"like_count": 2,
"bookmark_count": 0,
"liked_by": [
"emre",
"aa"
],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "Tim Drake: The Third Robin",
"content": "Let's talk about Tim Drake, the third Robin! Tim is known for his detective skills, rivaling even Batman's. He figured out Batman's identity and convinced Bruce Wayne to let him become Robin after the tragic death of Jason Todd. What's your favorite Tim Drake moment?",
"image_src": "https://tse4.mm.bing.net/th?id=OIP.OnZvoxr8jPS5kPtFCLIchgHaHa&pid=Api",
"qid": "Q1076696",
"qtitle": "Tim Drake",
"created_at": "2024-05-17T11:58:46.708067Z",
"updated_at": "2024-05-17T11:58:46.708123Z"
}
]
Sample API Call 3
http://164.90.189.150:8000/api/v2/search/?category=enemy%20of&qid=Q1621261
Q1621261 is the QID of Venom the comics character.
[
{
"id": 17,
"username": "aa",
"user_id": "11",
"like_count": 1,
"bookmark_count": 0,
"liked_by": [
"Tatü"
],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "title",
"content": "123",
"image_src": "",
"qid": "Q79037",
"qtitle": "Spider-Man",
"created_at": "2024-05-17T13:38:51.516627Z",
"updated_at": "2024-05-17T13:38:51.516682Z"
},
{
"id": 20,
"username": "tenacke",
"user_id": "10",
"like_count": 1,
"bookmark_count": 1,
"liked_by": [
"tenacke"
],
"is_liked": false,
"is_bookmarked": false,
"is_following": false,
"title": "Why Carnage Hates Venom",
"content": "Carnage despises Venom because of their twisted family dynamic. Born from Venom's symbiote, Carnage sees Venom as a father figure he must rebel against. Their differing ideologies and Carnage's inherent chaos further fuel their hatred. It's a brutal clash of family and ferocity!",
"image_src": "https://i.hizliresim.com/cxko7pn.jpg",
"qid": "Q1753328",
"qtitle": "Carnage",
"created_at": "2024-05-19T01:37:01.258307Z",
"updated_at": "2024-05-19T01:42:20.185308Z"
}
]
Both Posts about Carnage and Spider-Man are returned since they are both enemies of Venom.
Unit Tests for Search Post
def test_missing_parameters(self):
url = reverse("search_posts")
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_born_in_category(self, mock_born_in_wikidata):
url = reverse("search_posts")
response = self.client.get(url, {"qid": "Q123", "category": "born in"})
self.assertEqual(response.status_code, status.HTTP_200_OK)
Unit Tests for Wikidata Suggestions
def test_missing_keyword_parameter(self):
url = reverse("wikidata_suggestions")
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_valid_qid(self):
url = reverse("wikidata_suggestions")
response = self.client.get(url, {"keyword": "apple"})
self.assertEqual(response.status_code, status.HTTP_200_OK)
Challenges Faced During Implementation And Their Solutions
- I realized that me and my teammates started implementation without basic knowledge about Django and Django REST. Since we lacked theoretical knowledge, the project that we prepared before Milestone 2 was alien and hard to refactor for us. This resulted in building the backend app from scratch once more. This meant that we did not even have the register and login functionalities that we already built. Therefore, I have prepared three-paged tutorial where I introduced Models, Serializers, and Views. Their relationship is the core of the Django REST. However, it was already too late. This is why, as I mentioned in
Most Important Three Issues
, learning and preparing a tutorial about Django REST was important. - Since as a backend team we were already very late, the first join of the backend part and the frontend part of the code happened very late. Therefore, we could not have time to fix the code and have a properly working project.
- The most important difficulty was the management of time. Since we had other projects as challenging and time consuming as this one (especially 321 projects), we could not manage to focus on this project.
- For me, one of the most challenging part of the project was the stress management. We entered the last week and our team started to build the backend app from the start. They also started to use viewsets which I think were unnecessary and made the implementation hard because in order to effectively use a library, you had to know it well. Instead of this, building a view from scratch would be very helpful and easy for us to maintain the code. However, the disaggrement continued and we failed to create a properly working backend.
- Create Project Plan: This issue covers our overall project plan that we have done in the arly stages of the project. I have completed it with Ozan Karakaya and Muhamet Emin Çiftçi.
- Implement Login Page for Mobile: This issue covers the implementation of login-page, local storage method with "remember me" feature and navigation between screens. Also, authentication process is implemented in another issue which is connected with that issue.
- Implement the Post Component for Feed and Search Pages for the Mobile: This issue covers the implementation of post component which is implemented dynamically to be used in different pages.
- feat(mobile): add login screen #242:
- This PR covers the implementation of login screen to be used in authentication.
- feat(mobile): added async and storage methods #300:
- This PR adds more functionality to the login screen such as "remember me" feature to keep user logged in using local storage functions.
- feat(mobile): Post Screen and Navigation added #373
- This PR covers the implementation of Post Screen and Post Components which is clickable and they navigate through app.
- You can find the Project Plan Documentation in Wiki. We have planned our project detailly and created a documentation for our team to provide a good and readable plan with Ozan Karakaya and Muhammet Emin Çiftçi.
-
I have helped and contributed to the implementation of get
/api/v2/posts/
endpoint. Firstly, we need to login to get our token from the/api/v2/login/
endpoint by providing the credentials for our user. For the sample calls below, I will be using the token of@memin41
test user. Then, we are going to use our token and post endpoint withpost_id
. -
To use return of the information about any post, the
post_id
should be added at the end of the URL. Here, we wil return the post with relatedpost_id: 15
.
curl -X GET http://164.90.189.150/api/v2/posts/15/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzE2MTU3NDI4LCJpYXQiOjE3MTYwNzEwMjgsImp0aSI6IjdjYzNhNTdhOGM3ZDQ0OTE5N2I5MmE3ZjQzMWFkOGM1IiwidXNlcl9pZCI6Nn0.sCYavXIHGEv4LvdIzLxzPTgUHOxpLiPie3zpmWNCjvY"
- After using that, we can get information about the author of the post, post's like attributes , bookmark attributes, content, title and more.
{"id":15,"author_profile":
{"id":5,
"username":"ozankrk",
"email":"[email protected]",
"fullname":"Ozan Oytun",
"picture":"https://i.ibb.co/kHBtv0g/zenith.png",
"biography":"Interested in Marvel"},
"like_count":2,
"bookmark_count":1,
"liked_by":["ozankrk","Tatü"],
"is_liked":false,
"is_bookmarked":false,
"is_following":true,
"title":"The Genius Behind The Armor",
"content":"Let's chat about Iron Man! Tony Stark, the genius billionaire playboy philanthropist, is behind the iconic suit. His tech innovations and battles are legendary. What's your favorite Iron Man moment or suit?",
"image_src":"https://images.unsplash.com/photo-1635863138275-d9b33299680b?q=80&w=3731&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"qid":"Q180704",
"qtitle":"Iron Man",
"created_at":"2024-05-17T12:05:10.820919Z",
"updated_at":"2024-05-17T12:05:10.820974Z",
"author":5}
- If the token of the user to get this post is not given as header;
$ curl -X GET http://164.90.189.150/api/v2/posts/15/
-H "Content-Type: application/json"
- response code: 403
{"detail":"Authentication credentials were not provided."}
- I did not implement the unit test for this endpoint but I learnt how to code unit tests and how they work through our own documentation in wiki.
- The first challenge as a mobile team member was to learn and deep dive into mobile app dynamics. Since none of us as a mobile team have experiences, it was really hard to plan. We could not estimate the learning time cost exaclty because we were all unexperienced. Still, we succeed to be a good team and helped each other in every way to make everything easier for everyone. Everbody started to learn something about mobile development and did their job perfectly in the end.
- The second challenge for me was using typescript. We chose to use typescript in the beginning to write a safer code but it caused more problems than we expected since we were lack of information both typescript and mobile. So, we needed to spend extra time on typescript . But we handled that problem by taking help from the ones who know typescript properly and also using other sources.
- Another challenge was communication with backend team because one of the teams always had some problems and things didnt go as planned. That caused the teams to make some assumptions which caused issues such as wrong decisions on design. To solve this problem, one of our members was communicating with other team every day even if we do not encounter any specific problem.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Ümit Can Evleksiz, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Muhammed Emin Arayıcı, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Ozan Oytun Karakaya, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Yunus Kağan AYDIN, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Emre Kılıç, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Hasan Kerem Şeker, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Ceydanur Şen, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Mücahit Erdoğan Ünlü, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Arda Vural, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.
Related to the submission of all the project deliverables for the project of the CMPE 352 course, during the 2024 Spring semester, reported in this report, I, Muhammet Emin Çiftçi, declare that:
-
I am a student in the Computer Engineering program at Boğaziçi University and am registered for the CMPE 352 course during the 2024 Spring semester.
-
All the material that I am submitting related to my project (including but not limited to the project repository, the final project report, and supplementary documents) have been exclusively prepared by myself.
-
I have prepared this material individually without the assistance of anyone else with the exception of permitted peer assistance which I have explicitly disclosed in this report.