diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ddf53015..d5f4fb6d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,5 +1,5 @@ ## Repository Policy -All contributions to ARte must be tracked by an issue and at least one pull request. To start work on an issue you must fork ARte repository, pick an issue and when you have did your first commit on your fork you have to create a pull request to ARte devel branch so we can see your work in progress. The pull request name must follow this pattern: {STATE} {ISSUE NUMBER} - {ISSUE NAME}. Where {STATE} is the state of the pull request, all pull requests must be created with [WIP] tag and when you think you resolved the issue change to [REVIEW]. Example of pull request name: [WIP] 435 - Refactor create method. +All contributions to ARte must be tracked by an issue and at least one pull request. To start working on an issue you must fork ARte repository, create or pick an issue. Also check that there is no issue that already adheres to what you intend to post. To create your branch, follow the pattern: `feature/issueID-issue-title`. When you have did your first commit on your fork you have to create a pull request to ARte devel branch so we can see your work in progress. The pull request name must follow this pattern: `{STATE} {ISSUE NUMBER} - {ISSUE NAME}`. Where {STATE} is the state of the pull request, all pull requests must be created with [WIP] tag and when you think you resolved the issue change to [REVIEW]. Example of pull request name: [WIP] 435 - Refactor create method. ## Coding Style Make sure you are following our code style when submiting a pull request, following the style you make the process of reviewing your pull request better. @@ -8,7 +8,7 @@ Make sure you are following our code style when submiting a pull request, follow We use [flake8](http://flake8.pycqa.org/en/latest/) standard rules and [pep8](https://www.python.org/dev/peps/pep-0008/?) for code style. ### JavaScript code -We use [standardjs](https://standardjs.com/) for code style +We use [standardjs](https://standardjs.com/) for code style. ### HTML and Jinja2 Elements ids must init with the word "id" followed by a underscore and the name of the id e.g. ```html id="id_menu-bar"```. Elements classes only have the name e.g. ```html class="menu-bar"``` diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..8ad3a4fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug report +about: Report a bug to help us improve Jandig + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To reproduce the bug** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll the screen until '....' +4. See the error + +**Expected behavior** +A clear and concise description of what was expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Please, tell us which device/browser is used when finding the bug):** + - OS: [ex.: iOS], Browser [ex.: chrome], Version [ex.: 22] + +**Additional Information** +Add other information about the problem here, if necessary. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/issue_template.md b/.github/ISSUE_TEMPLATE/issue_template.md new file mode 100644 index 00000000..267eb373 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue_template.md @@ -0,0 +1,13 @@ +### Description: +Describe your issue briefly, inserting information necessary for understanding. + +### Acceptance criteria: +Describe what the issue needs to fulfill to be considered finalized. + +- + +### Tasks: +Checklist of actions to be taken. + +- [ ] + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..5c4be197 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +## Description + +A clear and concise description of what was made. + +## Resolves (Issues) + +Issues that have been resolved with this PR. + +## General tasks performed +* Task 1 +* Task 2 + +### Have you confirmed the application builds locally without error? See [here](https://github.com/memeLab/Jandig#running). +- [ ] Yes \ No newline at end of file diff --git a/README.md b/README.md index 84872a17..53817028 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ We are a small team based in Brazil :D talk to us on [Telegram](https://t.me/joi * @kisobral - [GitHub](https://github.com/KiSobral), [Instagram](https://www.instagram.com/hugsob/) * @rhuancpq - [GitHub](https://github.com/Rhuancpq), [Twitter](https://twitter.com/rhuancpq) * @thiagohersan - [GitHub](https://github.com/thiagohersan) +* @manuengsf - [Github](https://github.com/manuengsf) +* @darmsDD - [Github](https://github.com/darmsDD) +* @MatheusBlanco - [Github](https://github.com/MatheusBlanco) +* @devsalula - [Github](https://github.com/devsalula) +* @shayanealcantara [Github](https://github.com/shayanealcantara) +* @victoralvesgomide - [Github](https://github.com/victoralvesgomide) ### Collab We are looking for artists (both illustrators and animators) to create great content and help us testing the platform, people to translate our website from Portuguese to English (and vice versa), and developers to help us with the platform, please contact us via the Telegram channel or an issue on GitHub! @@ -35,10 +41,10 @@ You can find interviews and references to Jandig in the press [here](http://meme To contribute to Jandig ARte it would be awesome if you read [Contributing](https://github.com/memeLab/ARte/blob/master/.github/CONTRIBUTING.md) and our [Code of conduct](https://github.com/memeLab/ARte/blob/master/.github/CODE_OF_CONDUCT.md). After a good read you are ready to move foward! ### Prerequisites -We use docker and docker-compose to ensure a consistent development environment and to make the deploy process as painless possible, so all you need on your development tools to run Jandig ARte is [Docker](https://www.docker.com/) and [Docker-Compose](https://docs.docker.com/compose/overview/). +We use docker and docker-compose to ensure a consistent development environment and to make the deploy process as painless as possible, so all you need on your development tools to run Jandig ARte is [Docker](https://www.docker.com/) and [Docker-Compose](https://docs.docker.com/compose/overview/). ### Installing -Docker has good documentation on their website for installing docker and docker-compose for different operating systems like [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) and [Debian](https://docs.docker.com/install/linux/docker-ce/debian/). To install docker-compose choose your operating system [here](https://docs.docker.com/compose/install/) +Docker has good documentation on their website for installing docker and docker-compose for different operating systems like [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/) and [Debian](https://docs.docker.com/install/linux/docker-ce/debian/). To install docker-compose choose your operating system [here](https://docs.docker.com/compose/install/). ### Running To run Jandig ARte all you need to do is: @@ -54,13 +60,18 @@ docker-compose -f docker/docker-compose.yml up ``` If you get any error saying ``permission denied`` try run the command with sudo. ``` -sudo docker-compose up -f docker/docker-compose.yml +sudo docker-compose -f docker/docker-compose.yml up ``` Jandig ARte server will run at localhost. To test modifications you just need to run a web browser and access [localhost:8000](localhost:8000). If you want to test on a mobile device, you will need a https connection, we recommend [ngrok](https://www.npmjs.com/package/ngrok) to generate a https link for you. - - `sudo npm install -G ngrok` - - `ngrok http 8000` - - ngrok will prompt 3 links, select the one with `https` at beginning +``` +sudo snap install ngrok +ngrok http 8000 +``` + +ngrok will prompt 3 links: + ![usage](https://user-images.githubusercontent.com/12930004/54871980-ab41da00-4d9b-11e9-8b80-bb1d4bec420d.png) + +Select the one with `https` at beginning. diff --git a/docs/architecture-document.md b/docs/architecture-document.md new file mode 100644 index 00000000..94f17f36 --- /dev/null +++ b/docs/architecture-document.md @@ -0,0 +1,113 @@ +# Revision History + +|Version | description| Author(s) | date | +|--------|------------|-----------|------| +|1.0|Initial version|Victor Gomide & Emanuel Holanda|05/10/2020| +|1.1|New diagrams in PlantUml| VIctor Gomide & Emanuel Holanda |24/10/2020| + + +# Software Architecture Document (SAD) +## Introduction + +This document provides a complete architectural overview of the Jandig ARte project. In it, you’ll find the goals and constraints of architecture, the use-case view, the logical view, among others. + + +### Scope + +This document is extremely important for understanding the project as a whole, since architecture is the basis of all software. It is not only suitable for people who want to contribute to the project, but also so that the current team can remember and even change previous architectural decisions. + + +### Definitions, Acronyms, and Abbreviations + +- **SAD:** Software Architecture Document +- **App:** Application +- **MTV:** Model-Template-View +- **PWA:** Progressive Web App + + +### References + + - [Jandig ARte's Wiki](https://github.com/memeLab/Jandig/wiki/Jandig-ARte-architecture) + - [CSUN's Software Architecture Document Template](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjX4638opzsAhXlHrkGHfRtDwkQFjALegQIARAC&url=https%3A%2F%2Fprojects.cecs.pdx.edu%2Fattachments%2Fdownload%2F3180%2FSoftware_Architecture_Document_SF.docx&usg=AOvVaw0aIZsfpWJeIJ52HMgh7nXx) + - [Documento de Arquitetura de Software - Facom/UFU](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwi9m7T2rpzsAhVuF7kGHVbrBYwQFjACegQIARAC&url=http%3A%2F%2Fwww.facom.ufu.br%2F~flavio%2Fpds1%2Ffiles%2F2016-01%2Frup_sad-template-documento-arquitetura.dot&usg=AOvVaw3qyZZysozErnD64wCX-vOy) + - [Documento de Arquitetura de Software RDI-AEE](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiE78LEr5zsAhV7GLkGHSWyAVMQFjAAegQIBRAC&url=http%3A%2F%2Frepositorio.aee.edu.br%2Fbitstream%2Faee%2F1106%2F3%2FTCC2_2018_2_GabrielLeiteDias_MatheusLimadeAlbuquerque_Apendice2.pdf&usg=AOvVaw2wXEOkYpBHmN32ChHHDgOh) +- [The Django Book: Django's Structure](https://djangobook.com/mdj2-django-structure/) + +### Overview + +In order to explain Jandig ARte's architecture from different points of views, here's an approach of the next topics: + +- **Architectural Representation:** architecture of the software as a whole. +- **Architectural Goals and Constraints:** non-functional requirements we want to achieve through Jandig. +- **Use-Case View:** expected behavior from users of Jandig's functionalities. +- **Logical View:** the internal organization of code, its packages, layers and classes. + + +## Architectural Representation + +Project's main programming language is Python, through Django framework. Django uses an exclusive architecture called **MTV (Model-Template-View)**, in which **Model** represents the data layer, **Template** represents user's interface and **View** acts as an intermediary layer between them: + +![](images/mtv-architecture-diagram.png) + +Jandig ARte is a **Progressive Web App (PWA)**, which means it is an web app that has a similar use to a native mobile app. It uses **PostgreSQL** as database. + + +## Architectural Goals and Constraints + +Jandig was created for providing a low-cost and easy-to-use augmented reality experience to artists and art contemplators. That said, the software must be: + +- Easy to learn, use and memorize; +- Usable through a smartphone, allowing more people to use it; +- No previous knowledge of programming necessary for using it; +- Free, or cheap enough; +- Available in different languages, so people around the world can use it; +- Open Source, so community can work together for making it awesome! + + +## Use-Case View +### Account Access and Management + +The diagram below shows how account access and management is done, with users and system as actors. Please note that Visitor is an user that hasn't log in the app. + +![](images/use-case-diagram-user.png) + + +### Artist Role + +The following diagram shows the application's features focused on the Artist's role. + + +![](images/use-case-diagram-artist.png) + + +### Other Features + +Below are shown some other interesting features from Jandig ARte: + +![](images/use-case-diagram-features.png) + + +## Logical View +### Overview + +Since the software is Django-based, it contains projects, apps and layers. in Jandig ARte case, we have two main apps: "core" and "users". + +![](images/package-diagram-logical-view.png) + + +### Architecturally Significant Design Packages + +#### "Profile" Class Diagram +![](images/class-diagram-profile.png) + +#### "Marker" Class Diagram +![](images/class-diagram-marker.png) + +#### "Artwork" Class Diagram +![](images/class-diagram-artwork.png) + +#### "Object" Class Diagram +![](images/class-diagram-object.png) + +#### "Exhibit" Class Diagram +![](images/class-diagram-exhibit.png) diff --git a/docs/images/artwork-button.png b/docs/images/artwork-button.png new file mode 100644 index 00000000..d7f7e863 Binary files /dev/null and b/docs/images/artwork-button.png differ diff --git a/docs/images/artwork-page.png b/docs/images/artwork-page.png new file mode 100644 index 00000000..1368a5c9 Binary files /dev/null and b/docs/images/artwork-page.png differ diff --git a/docs/images/class-diagram-artwork.png b/docs/images/class-diagram-artwork.png new file mode 100644 index 00000000..8987e052 Binary files /dev/null and b/docs/images/class-diagram-artwork.png differ diff --git a/docs/images/class-diagram-exhibit.png b/docs/images/class-diagram-exhibit.png new file mode 100644 index 00000000..bb6dbc82 Binary files /dev/null and b/docs/images/class-diagram-exhibit.png differ diff --git a/docs/images/class-diagram-marker.png b/docs/images/class-diagram-marker.png new file mode 100644 index 00000000..746e2588 Binary files /dev/null and b/docs/images/class-diagram-marker.png differ diff --git a/docs/images/class-diagram-object.png b/docs/images/class-diagram-object.png new file mode 100644 index 00000000..d39eeb0e Binary files /dev/null and b/docs/images/class-diagram-object.png differ diff --git a/docs/images/class-diagram-profile.png b/docs/images/class-diagram-profile.png new file mode 100644 index 00000000..146a3ae7 Binary files /dev/null and b/docs/images/class-diagram-profile.png differ diff --git a/docs/images/exhibition-created.png b/docs/images/exhibition-created.png new file mode 100644 index 00000000..039adffa Binary files /dev/null and b/docs/images/exhibition-created.png differ diff --git a/docs/images/exhibition-details.png b/docs/images/exhibition-details.png new file mode 100644 index 00000000..9ba966c5 Binary files /dev/null and b/docs/images/exhibition-details.png differ diff --git a/docs/images/exhibition-main-page.png b/docs/images/exhibition-main-page.png new file mode 100644 index 00000000..f864636b Binary files /dev/null and b/docs/images/exhibition-main-page.png differ diff --git a/docs/images/exhibition-select-artwork-button.png b/docs/images/exhibition-select-artwork-button.png new file mode 100644 index 00000000..62783027 Binary files /dev/null and b/docs/images/exhibition-select-artwork-button.png differ diff --git a/docs/images/exhibition-select-artwork.png b/docs/images/exhibition-select-artwork.png new file mode 100644 index 00000000..09f37703 Binary files /dev/null and b/docs/images/exhibition-select-artwork.png differ diff --git a/docs/images/finish-art.png b/docs/images/finish-art.png new file mode 100644 index 00000000..4e4832ea Binary files /dev/null and b/docs/images/finish-art.png differ diff --git a/docs/images/main-page-jandig.png b/docs/images/main-page-jandig.png new file mode 100644 index 00000000..2b7809aa Binary files /dev/null and b/docs/images/main-page-jandig.png differ diff --git a/docs/images/main-page-logged.png b/docs/images/main-page-logged.png new file mode 100644 index 00000000..0807a71a Binary files /dev/null and b/docs/images/main-page-logged.png differ diff --git a/docs/images/marker-generator.png b/docs/images/marker-generator.png new file mode 100644 index 00000000..4881d461 Binary files /dev/null and b/docs/images/marker-generator.png differ diff --git a/docs/images/mtv-architecture-diagram.png b/docs/images/mtv-architecture-diagram.png new file mode 100644 index 00000000..aea07d12 Binary files /dev/null and b/docs/images/mtv-architecture-diagram.png differ diff --git a/docs/images/package-diagram-logical-view.png b/docs/images/package-diagram-logical-view.png new file mode 100644 index 00000000..0a69e512 Binary files /dev/null and b/docs/images/package-diagram-logical-view.png differ diff --git a/docs/images/plantUML/class-diagram-artwork.puml b/docs/images/plantUML/class-diagram-artwork.puml new file mode 100644 index 00000000..555dd1ce --- /dev/null +++ b/docs/images/plantUML/class-diagram-artwork.puml @@ -0,0 +1,17 @@ +@startuml + +hide circle + +class "Artwork (models.Model)" as C { + {field} - author: models.ForeignKey() + {field} - marker: models.ForeignKey() + {field} - augmented: models.ForeignKey() + {field} - title: models.CharField() + {field} - description: models.TextField() + {field} - created_at: models.DateTimeField() + {method} + exhibits_count(self) + {method} + exhibits_list(self) + {method} + in_use(self) +} + +@enduml diff --git a/docs/images/plantUML/class-diagram-exhibit.puml b/docs/images/plantUML/class-diagram-exhibit.puml new file mode 100644 index 00000000..8902e421 --- /dev/null +++ b/docs/images/plantUML/class-diagram-exhibit.puml @@ -0,0 +1,16 @@ +@startuml + +hide circle + +class "Exhibit (models.Model)" as C { + {field} - owner: models.ForeignKey() + {field} - name: models.CharField() + {field} - slug: models.CharField() + {field} - artworks: models.ManyToManyField() + {field} - creation_date: models.DateTimeField() + {method} + __str__(self) + {method} + artworks_count(self) + {method} + date(self) +} + +@enduml \ No newline at end of file diff --git a/docs/images/plantUML/class-diagram-marker.puml b/docs/images/plantUML/class-diagram-marker.puml new file mode 100644 index 00000000..1f020659 --- /dev/null +++ b/docs/images/plantUML/class-diagram-marker.puml @@ -0,0 +1,20 @@ +@startuml + +hide circle + +class "Marker (models.Model)" as C { + {field} - owner: models.ForeignKey() + {field} - source: models.ImageField() + {field} - uploaded_at: models.DateTimeField() + {field} - author: models.CharField() + {field} - title: models.CharField() + {field} - patt: models.FileField() + {method} + __str__(self) + {method} + artworks_count(self) + {method} + artworks_list(self) + {method} + exhibits_count(self) + {method} + exhibits_list(self) + {method} + in_use(self) +} + +@enduml diff --git a/docs/images/plantUML/class-diagram-object.puml b/docs/images/plantUML/class-diagram-object.puml new file mode 100644 index 00000000..1fb01cb8 --- /dev/null +++ b/docs/images/plantUML/class-diagram-object.puml @@ -0,0 +1,31 @@ +@startuml + +hide circle + +class "Object (models.Model)" as C { + {field} - owner: models.ForeignKey() + {field} - source: models.FileField() + {field} - uploaded_at: models.DateTimeField() + {field} - author: models.CharField() + {field} - title: models.CharField() + {field} - scale: models.CharField() + {field} - position: models.CharField() + {field} - rotation: models.CharField() + {method} + __str__(self) + {method} + artworks_count(self) + {method} + artworks_list(self) + {method} + exhibits_count(self) + {method} + exhibits_list(self) + {method} + in_use(self) + {method} + xproportion(self) + {method} + yproportion(self) + {method} + xscale(self) + {method} + yscale(self) + {method} + fullscale(self) + {method} + xposition(self) + {method} + yposition(self) +} + +@enduml + + diff --git a/docs/images/plantUML/class-diagram-profile.puml b/docs/images/plantUML/class-diagram-profile.puml new file mode 100644 index 00000000..dde335f8 --- /dev/null +++ b/docs/images/plantUML/class-diagram-profile.puml @@ -0,0 +1,14 @@ +@startuml + +hide circle + +class "Profile (models.Model)" as C { + {field} - user: models.OneToOneField() + {field} - bio: models.TextField() + {field} - country: models.CharField() + {field} - personal_site: models.UrlField() + {method} + create_user_profile(sender, instance, created, **kwarg) + {method} + save_user_profile(sender, instance, **kwargs) +} + +@enduml diff --git a/docs/images/plantUML/mtv-architecture-diagram.puml b/docs/images/plantUML/mtv-architecture-diagram.puml new file mode 100644 index 00000000..24c079b2 --- /dev/null +++ b/docs/images/plantUML/mtv-architecture-diagram.puml @@ -0,0 +1,24 @@ +@startuml + +left to right direction + +rectangle "Client Side" as C { + rectangle "Django Template" as DT +} + +rectangle "Server Side" as S { + rectangle "Django Framework" as DF { + rectangle "App Logic" as AL + rectangle "View Logic" as VL + rectangle "Model" as M + } + database "Database" as DB +} + +DT <--> AL +DT <--> VL +AL <--> M +VL <--> M +M <--> DB + +@enduml \ No newline at end of file diff --git a/docs/images/plantUML/package-diagram-logical-view.puml b/docs/images/plantUML/package-diagram-logical-view.puml new file mode 100644 index 00000000..78318bf7 --- /dev/null +++ b/docs/images/plantUML/package-diagram-logical-view.puml @@ -0,0 +1,22 @@ +@startuml + +hide circle + +package ArTE <> { + package users <> { + package "models.py" as M1 { + class Profile + class Marker + class Artwork + class Object + } + } + + package core <> { + package "models.py" as M2 { + class Exhibit + } + } +} + +@enduml diff --git a/docs/images/plantUML/use-case-diagram-artist.puml b/docs/images/plantUML/use-case-diagram-artist.puml new file mode 100644 index 00000000..9cb01519 --- /dev/null +++ b/docs/images/plantUML/use-case-diagram-artist.puml @@ -0,0 +1,39 @@ +@startuml + +left to right direction + +actor "Artist" as A +actor "Other users" as OU + +rectangle { + usecase "Upload marker" as UC1 + usecase "Upload object" as UC2 + usecase "Create artwork" as UC3 + usecase "Try artwork out" as UC4 + usecase "Edit artwork" as UC5 + usecase "Delete artwork" as UC6 + usecase "Create exhibition" as UC7 + usecase "Edit exhibition" as UC8 + usecase "Delete exhibition" as UC9 + usecase "View itens uploaded by Artist" as UC10 + usecase "Download itens uploaded by Artist" as UC11 +} + +' Artist's relationships +A -- UC1 +A -- UC2 +A -- UC3 +A -- UC4 +A -- UC5 +A -- UC6 +A -- UC7 +A -- UC8 +A -- UC9 +A -- UC10 +A -- UC11 + +' Other users' relationships +UC10 -- OU +UC11 -- OU + +@enduml diff --git a/docs/images/plantUML/use-case-diagram-features.puml b/docs/images/plantUML/use-case-diagram-features.puml new file mode 100644 index 00000000..c3e9efa3 --- /dev/null +++ b/docs/images/plantUML/use-case-diagram-features.puml @@ -0,0 +1,18 @@ +@startuml + +left to right direction + +actor "Visitor" as V + +rectangle { + usecase "Interact with exhibitions" as UC1 + usecase "Change app language" as UC2 + usecase "Access help section" as UC3 +} + +' Visitor's relationships +V -- UC1 +V -- UC2 +V -- UC3 + +@enduml \ No newline at end of file diff --git a/docs/images/plantUML/use-case-diagram-user.puml b/docs/images/plantUML/use-case-diagram-user.puml new file mode 100644 index 00000000..629746a5 --- /dev/null +++ b/docs/images/plantUML/use-case-diagram-user.puml @@ -0,0 +1,39 @@ +@startuml + +left to right direction + +actor "Visitor" as V +actor "User" as U +actor "Jandig ArTE" <> as J + +rectangle { + usecase "View registration form" as UC1 + usecase "Register" as UC2 + usecase "View login form" as UC3 + usecase "Recover password" as UC4 + usecase "Login" as UC5 + usecase "View home page" as UC6 + usecase "Edit account data" as UC7 + usecase "Delete account" as UC8 + usecase "Log out" as UC9 +} + +' Visitor's relationships +UC1 -- V +V -- UC2 + +' User's relationships +UC3 -- U +U -- UC4 +U -- UC5 +UC6 -- U +U -- UC7 +U -- UC8 +U -- UC9 + +' System's relationships +UC1 -- J +UC3 -- J +UC6 -- J + +@enduml \ No newline at end of file diff --git a/docs/images/select-marker.png b/docs/images/select-marker.png new file mode 100644 index 00000000..5b489996 Binary files /dev/null and b/docs/images/select-marker.png differ diff --git a/docs/images/select-object.png b/docs/images/select-object.png new file mode 100644 index 00000000..256c1dc4 Binary files /dev/null and b/docs/images/select-object.png differ diff --git a/docs/images/sign-up-page.png b/docs/images/sign-up-page.png new file mode 100644 index 00000000..99572f1e Binary files /dev/null and b/docs/images/sign-up-page.png differ diff --git a/docs/images/upload-marker.png b/docs/images/upload-marker.png new file mode 100644 index 00000000..66500269 Binary files /dev/null and b/docs/images/upload-marker.png differ diff --git a/docs/images/upload-object.png b/docs/images/upload-object.png new file mode 100644 index 00000000..4eb230e4 Binary files /dev/null and b/docs/images/upload-object.png differ diff --git a/docs/images/use-case-diagram-artist.png b/docs/images/use-case-diagram-artist.png new file mode 100644 index 00000000..431434a0 Binary files /dev/null and b/docs/images/use-case-diagram-artist.png differ diff --git a/docs/images/use-case-diagram-features.png b/docs/images/use-case-diagram-features.png new file mode 100644 index 00000000..037e35b1 Binary files /dev/null and b/docs/images/use-case-diagram-features.png differ diff --git a/docs/images/use-case-diagram-user.png b/docs/images/use-case-diagram-user.png new file mode 100644 index 00000000..5eac527b Binary files /dev/null and b/docs/images/use-case-diagram-user.png differ diff --git a/docs/index.rst b/docs/index.rst index 17e43c17..b051a821 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,4 +11,5 @@ Ajuda animacoes marcadores - publicando-obras + publicando-obras-ingles + publicando-obras-portugues diff --git a/docs/publicando-obras-ingles.rst b/docs/publicando-obras-ingles.rst new file mode 100644 index 00000000..a9137d0e --- /dev/null +++ b/docs/publicando-obras-ingles.rst @@ -0,0 +1,236 @@ +How to publish content in augmented reality in Jandig +======================================================= + +Welcome to Jandig ARte! + +For the newcomer artists and users, we would like to express our gratitude for having chose this platform as a tool for exhibiting your Artworks. + +In this manual we will guide you, step-by-step, on how to create your own Augmented Reality based art pieces. We will also explain how the system works in a meaningful way, with some core concepts, so that you will know all the steps to be taken and how they affect your art. Concepts such as Markers, Objects, how they corelate to create an Artwork and an Exhibition. + +Let's get right to it, for this is a quick and essential read for those who want to use Jandig as their main AR art creator. + +Quickstart tutorial +~~~~~~~~~~~~~~~ + +1) Go to "https://jandig.app/generator". Upload the image to be used in the Marker without the black border (it will be added by the application). Download the Marker (Download .PATT Marker) and the image (Download image Marker) and store the files in a safe place. If you want, download PDFs with Markers for printing. +Important: set the Patern Ratio to 0.60. + +2) Go to "http://jandig.art" and create an account. + +3) Click on "Upload Marker" and upload the image (with extension ".PNG") and Marker (".PATT") created in the previous step. This image is the one that the Jandig camera will recognize. + +4) Click on "Upload Object" and upload the GIF or video (WEBM or MP4 format) with your animation. This image Jandig will display over the camera. + +5) Click on "Create Jandig Artwork", choose the corresponding Marker and Object you just uploaded. An Artwork is the set of Marker and Object, linking to be presented in augmented reality. + +6) Click on "Create Exhibition". Choose one or several works. Give the set a title and define its URL. It will be used to access the set of Artworks created. For example, if you enter "expotest" the definitive URL to access your creations will be "https://jandig.app/expotest". + +Access the final URL you just created, point the camera at the Marker and watch the magic happen! + + +Tutorial - Learn the basics +~~~~~~~~~~~ + +Before anything else, an account need to be created, so that artists can deploy their pieces. It is not needed for those who only desire to appreciate an Artwork, but for those who want to actively work with art, it is essential. + +To do that, please refer to the steps below. + +1) Access Jandig's website by clicking in the appropriate `URL`_, and click the "Sign up" button. + +.. _URL: jandig.app + +.. _image: https://jandig.app/users/signup/ + +.. figure:: ../docs/images/main-page-jandig.png + :scale: 50% + :alt: Jandig main screen + :target: jandig.app + + Jandig main screen + + + +2) Fill the spaces with your informations, as shown in the `image`_, and submit it! + +.. figure:: ../docs/images/sign-up-page.png + :scale: 50% + :alt: Sign up page + :target: jandig.app/users/signup + + Sign up page + + +3) Congratulations! You have succesfully created your Jandig ARte account and can now actively contribute to the art community with your AR-based pieces! + +.. figure:: ../docs/images/main-page-logged.png + :scale: 50% + :alt: Post-login page + :target: jandig.app + + Post-login page + + +So now the next step would be to produce (and publish) your very first Artwork. To do that, there are a few concepts to go through before you can start. + +Let's take a look at them. + +Markers +~~~~~~~~ + +Markers are the very basis of your future Artwork. They are essentially an image, made by you, or not, that is processed so that it can be succesfully read by Jandig and present your Artwork. + +They caracteristically have a black border that is inserted around the drawing, and this border serves for Jandig to recognize the Markers. + +To create a Marker, all you need to have with you is your image. It can be anything, from a painting to a random picture you saved from Google Images. Jandig will do all the work of processing and generating your Marker. + +To do that, head to this `page`_, and submit your image for Marker generation. Take a look at the imagem down below to see what it looks like, and where to upload your image. + +.. _page: https://jandig.app/generator/ + +.. figure:: ../docs/images/marker-generator.png + :scale: 50% + :alt: Marker generator page + :target: https://jandig.app/generator/ + + Marker generator page + +Ok, so now that you have uploaded your image, go ahead and download the two files that will be given to you by Jandig, the .patt Marker file and the image Marker file. For the sake of brevity and simplicity of this manual, the pattern file (.patt) is the file created and used by most AR toolkits as the pattern the AR technology will recognize. + +Store these two files in a safe location, for safekeeping. + +Now all you have to do is upload the file! Go back to the application's `main`_ page and select the button that says "Upload Marker". You will be greeted by this screen. + +.. _main: https://jandig.app + +.. figure:: ../docs/images/upload-marker.png + :scale: 50% + :alt: Marker upload page + :target: https://jandig.app/users/markers/upload/ + + Marker upload page + +This is where you will submit your Marker, so go ahead and fill the spaces with information like title and author's name, in case you're not the Marker's creator, as well as choosing from your device the appropriate Marker image (that .png file from before) and the Marker pattern (that .patt file from before). Don't forget to read all the informations the page contain. + +Voila! You have succesfully created and added to your collection an AR Marker. For the next step, we will be creating an Object! + +Objects +~~~~~~~~ + +When you upload a Marker, the application will re-direct you to the main page again. From there, look for the button that says "Upload Object", which is right below the "Upload Marker" button. Go ahead and click it, and the application will lead you to this `page`_ right here. + +.. figure:: ../docs/images/upload-object.png + :scale: 50% + + Object upload page + +In this page, you will submit your Object. In Jandig terms, the Object is the animation that will show up in your screen when you read the Marker throgh your device's camera. It is the real magic of AR and the one which all the work before will be useful for. So let's take a look at the page and learn how to upload an Object. + +While this submission form is bigger, the process is much simpler. Before filling it out, select and locate the file you want to upload. The formats currently supported in Jandig are .gif, .webm (including transparency) and .mp4. + +There are no restrictions on size, theme, looping and other specifications, but we recommend that you choose content that has a perfect loop and is related to the Marker theme. Also, do not restrict yourself to using a file that you have found on the internet or on social media. Go ahead and use all your artistic skills to create your own! + +Now is the time to keep in mind that scale and position of the Object will affect the Artwork. There are two fields where you can fill with numbers related to those two parameters: + +1) The scale parameter, which is set by default to 1. If you want your image to be bigger, say twice the size, just change this number to 2. If you want it to be three times it's original size, set it to 3, and so on for other sizes. This also applies for smaller sizes and decimals, such as 0.5 will be half the original Objects size. +2) The position parameter, which should be adjusted relative to the size of the Object on the screen. This one is further broke down into another two different parameters, horizontal and vertical. These two parameters can be better understood taking in consideration a graph. Their default values will be set to 0, which marks the center of the graph, where the horizontal and vertical lines intersect. Let's take a look at how to tamper with them: + a) Horizontal: If the value is positive and is 2, for example, the center of the Object will be placed in a distance 2 times the size of it's Marker side to the right. If this value is negative, say -2, it will be placed at the same distance 2 times the size of it's Marker side to the left. + b) Vertical: If the value is positive and is 2, for example, the center of the Object will be placed in a distance 2 times the size of it's Marker side, above it. If this value is negative, say -2, it will be placed at the same distance 2 times the size of it's Marker side, below it. + +After you have succesfully uploaded your image, and set your values, don't forget to give it a title and say whether you're its author or not. + +Voila! You have succesfully created your Markers Object and can now create your Artwork! Remember that these two, Marker and Object, are not yet linked to one another. This will happen in the next step. + +Artworks +~~~~~~~~~ + +Ok, so now that we have gone through everything we needed to get done to create an Artwork, let's get to the process of actually creating it. A Jandig Artwork is defined by the junction of two things that will work together to create the interaction that we want to achieve. + +You guessed it right, we will need to make use of the previously created Marker and Object. In this section we will select one Marker and one Object so that the magic can be done and an AR Artwork can be seen through your device's camera. Head back to Jandig's main page once again and look for this button: + +.. figure:: ../docs/images/artwork-button.png + :scale: 70% + + Create Artwork button + + + +Click it, and you will be redirected to a page that looks like this: + +.. figure:: ../docs/images/artwork-page.png + :scale: 60% + + Select Marker and Object page + + +The process is pretty straight forward and simple and pratically the same for both itens. You will be greeted by a pop-up with a lot of Markers, and Objects in their case, or none. In the case of this manual ExampleUser, all of the test case Markers and Objects appeared. + +Simply select one Marker, aggree to the terms and go press next to select one Object. Here's an example of selected Marker and Object: + +.. figure:: ../docs/images/select-marker.png + :scale: 50% + + Select Marker from collection page + +.. figure:: ../docs/images/select-object.png + :scale: 50% + + Select Object from collection page + +Give a title and a description and you're done! + +.. figure:: ../docs/images/finish-art.png + :scale: 50% + + Description about Artwork page + +Voila! You have succesfully created your first Jandig Artwork and are almost finished with this manual! + + +Exhibitions +~~~~~~~~~~~~ + +Welcome to the last step! In this final phase, we will show you how to exhibit your Artwork to the world, using the process of creating an Exhibition. It is through exhibitions that the gerenal public, which include common users and even other artists, will have access to and be able to interact with your Artworks. + +To get started, simply access the "Create Exhibition" icon. + +.. figure:: ../docs/images/exhibition-main-page.png + :scale: 30% + :target: https://jandig.app/users/exhibits/create/ + + Create Exhibition icon page + +Next, you need to confirm that you want to select Artwork from the collection. + +.. figure:: ../docs/images/exhibition-select-artwork-button.png + :scale: 30% + :target: https://jandig.app/users/exhibits/create/ + + Select Artwork button + + +Among the Artworks in the collection, search for and select one or more that you want to expose. + +.. figure:: ../docs/images/exhibition-select-artwork.png + :scale: 30% + + Select Artworks from collection + + +After selecting one or more Artworks, give your Exhibition a title and define its URL. This URL will be used to access the set of Artworks selected to your exhibition. For example, if you enter "expos" the definitive URL to access your creation will be "https://jandig.app/expos". + +.. figure:: ../docs/images/exhibition-details.png + :scale: 30% + + Details about your exhibition page + + +Access the final URL you just created, point the camera at the Marker and watch the magic happen! + +You can see all your Exhibitions in the "My stuff" menu. And you can also access directly from there, clicking in "See this Exhibition". + +.. figure:: ../docs/images/exhibition-created.png + :scale: 30% + + Exhibition created page + +And that's it! If you have got to this step, you have succesfully created and displayed your very own AR Artworks to the world. Congrats on making it this far, and enjoy all the experiences that jandig has to offer! \ No newline at end of file diff --git a/docs/publicando-obras-portugues.rst b/docs/publicando-obras-portugues.rst new file mode 100644 index 00000000..5a5668dd --- /dev/null +++ b/docs/publicando-obras-portugues.rst @@ -0,0 +1,232 @@ +Como publicar conteúdo em realidade aumentada no Jandig +======================================================= + +Bem-vindo ao Jandig ARte! + +Para os recém-chegados artistas e utilizadores, gostaríamos de expressar os nossos agradecimentos por terem escolhido esta plataforma como uma ferramenta para expor suas Obras Jandig. + + +Neste manual iremos guiá-lo, passo a passo, sobre como criar as suas próprias peças de arte baseadas na tecnologia de Realidade Aumentada. Explicaremos também como o sistema funciona de uma forma significativa, com alguns conceitos centrais, para que conheça todos os passos a dar e como eles influenciam a sua arte. Conceitos tais como Marcadores, Objetos, como eles se co-relacionam para criar uma Obra Jandig e uma Exposição. + +Vamos direto ao assunto, pois esta é uma leitura rápida e essencial para aqueles que querem utilizar o Jandig como o seu principal criador de arte AR. + +Tutorial de Iniciação Rápida +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Acesse “https://jandig.app/generator”. Faça upload da imagem a ser utilizada no Marcador sem a borda preta (ela será adicionada pelo aplicativo). Baixe o Marcador (Download .PATT Marker) e a imagem (Download image Marker) e guarde os arquivos em um local seguro. Se quiser, baixe PDFs com os Marcadores para impressão. Importante: colocar o Patern Ratio como 0.60. + +Acesse “http://jandig.art” e crie uma conta. + +Clique em “Enviar Marcador” e suba a imagem (com extensão “.PNG”) e Marcador (“.PATT”) criadas na etapa anterior. Esta imagem é a que a câmera do Jandig reconhecerá. + +Clique em “Enviar Objeto” e faça upload do GIF ou vídeo (nos formatos WEBM ou MP4) com a sua animação. Esta imagem o Jandig exibirá sobre a da câmera. + +Clique em “Criar Obra Jandig”, escolha o Marcador e Objeto correspondente que você acabou de subir. Uma Obra Jandig é o conjunto do Marcador e Objeto, vinculando para ser apresentado em realidade aumentada. + +Clique em “Criar Exposição”. Escolha uma ou várias Obras. Dê um título para o conjunto e defina sua URL. Ela será usada para acessar o conjunto de Obras criado por você. Por exemplo, se você inserir “expoteste” a URL definitiva para acessar sua(s) criações será “https://jandig.app/expoteste”. + +Acesse a URL definitiva que você acabou de criar, aponte a câmera para o Marcador e veja a mágica acontecer! + +Tutorial - Aprenda o básico +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Antes de mais, é necessário criar uma conta, para que os artistas possam distribuir as suas peças. Não é necessário para aqueles que apenas desejam apreciar uma Obra Jandig, mas para aqueles que querem trabalhar ativamente com a plataforma, é essencial. + +Para tal, por favor consulte os passos abaixo. + +1) Acesso o website do Jandig clicando no `URL`_ apropriado, e clique no botão "Sign up". + +.. _URL: jandig.app + +.. _imagem: https://jandig.app/users/signup/ + +.. figure:: ../docs/images/main-page-jandig.png + :scale: 50% + :alt: Página principal do Jandig + :target: jandig.app + + Página principal do Jandig + + + +2) Preencha os espaços com as suas informações, como mostra a `imagem`_, e submeta-a! + +.. figure:: ../docs/images/sign-up-page.png + :scale: 50% + :alt: Página de cadastro + :target: jandig.app/users/signup + + Página de cadastro + + +3) Parabéns! Você criou com sucesso a sua conta Jandig ARte e pode agora contribuir ativamente para a comunidade artística com as suas peças baseadas em AR! + +.. figure:: ../docs/images/main-page-logged.png + :scale: 50% + :alt: Página pós-login + :target: jandig.app + + Página pós-login + +O passo seguinte seria produzir (e publicar) a sua primeira Obra Jandig. Para que possamos fazer tal tarefa, existem alguns conceitos a serem passados antes de poder começar. + +Vamos dar uma olhada neles. + +Marcadores +~~~~~~~~~~ + +Os Marcadores são a própria base de seu futuro trabalho artístico. Eles são essencialmente uma imagem feita por você, ou não, que é processada para que possa ser lida com sucesso pelo Jandig e apresentar sua Obra Jandig. + +Caracteristicamente, eles têm uma borda preta que é inserida ao redor do desenho, e esta borda serve para o Jandig reconhecer os Marcadores. + +Para criar um Marcador, tudo o que você precisa ter com você é sua imagem. Pode ser qualquer coisa, uma pintura ou uma imagem aleatória que você salvou do Google. Jandig fará todo o trabalho de processamento e geração de seu Marcador. + +Para isso, vá até esta `página`_, e envie sua imagem para a geração de Marcadores. Dê uma olhada na imagem abaixo para ver como ela se parece, e onde carregar sua imagem. + +.. _página: https://jandig.app/generator/ + +.. figure:: ../docs/images/marker-generator.png + :scale: 50% + :alt: Página de geração de Marcador + :target: https://jandig.app/generator/ + + Página de geração de Marcador + +Ok, agora que você fez o upload de sua imagem, vá em frente e baixe os dois arquivos que lhe serão fornecidos pelo Jandig, o arquivo .patt Marker e o arquivo image Marker. Por uma questão de brevidade e simplicidade deste manual, o arquivo padrão (.patt) é o arquivo criado e usado pela maioria dos toolkits AR como o padrão que a tecnologia AR irá reconhecer. + + +Armazene estes dois arquivos em um local seguro, por segurança. + +Agora tudo o que você precisa fazer é subir o arquivo! Volte à página principal do aplicativo e selecione o botão que diz "Upload Marker". Você será recebido por esta tela. + +.. _main: https://jandig.app + +.. figure:: ../docs/images/upload-marker.png + :scale: 50% + :alt: Página de upload de Marcador + :target: https://jandig.app/users/markers/upload/ + + Página de upload de Marcador + +É aqui que você enviará seu Marcador, então vá em frente e preencha os espaços com informações como título e nome do autor, caso você não seja o criador do Marcador, além escolher de seu dispositivo a imagem do Marcador apropriada (aquele arquivo .png de antes) e o padrão do Marcador (aquele arquivo .patt de antes). Não se esqueça de ler todas as informações que a página contém. + +Voilá! Você criou com sucesso e adicionou à sua coleção um Marcador de AR. Para o próximo passo, estaremos criando um Objeto! + +Objetos +~~~~~~~ + +Quando você carregar um Marcador, o aplicativo o redirecionará para a página principal novamente. De lá, procure o botão que diz "Upload Object", que está logo abaixo do botão "Upload Marker". Vá em frente e clique nele, e o aplicativo o levará a esta `página`_. + +.. figure:: ../docs/images/upload-object.png + :scale: 50% + + Página de carregamento de Objetos + +Nesta página, você enviará seu Objeto. Em termos do Jandig, o Objeto é a animação que aparecerá em sua tela quando você ler o Marcador através da câmera do seu dispositivo. É a verdadeira magia da AR e aquela para a qual todo o trabalho anterior servirá. Portanto, vamos dar uma olhada na página e aprender como carregar um Objeto. + +Embora este formulário de envio seja maior, o processo é muito mais simples. Antes de preenchê-lo, selecione e localize o arquivo que você deseja carregar. Os formatos suportados atualmente no Jandig são .gif, .webm (inclusive com transparência) e .mp4. + +Não há restrições quanto ao tamanho, tema, looping e outras especificações, mas recomendamos que você escolha um conteúdo que tenha um loop perfeito e seja relacionado à temática do Marcador. Além disso, não se restrinja a usar um arquivo que você tenha encontrado na internet ou em mídias sociais. Vá em frente e use todas as suas habilidades artísticas para criar o seu próprio! + +Agora é o momento de ter em mente que a escala e a posição do Objeto afetará o trabalho artístico. Há dois campos onde você pode preencher com números relacionados a esses dois parâmetros: + +1) O parâmetro de escala, que é definido por padrão como 1. Se você quiser que sua imagem seja maior, digamos duas vezes o tamanho, basta mudar este número para 2. Se você quiser que seja três vezes o tamanho original, defina-o para 3, e assim por diante para outros tamanhos. Isto também se aplica para tamanhos menores e decimais, tais como 0,5 será metade do tamanho original do Objeto. +2) O parâmetro de posição, que deve ser ajustado em relação ao tamanho do Objeto na tela. Este é ainda dividido em outros dois parâmetros diferentes, horizontal e vertical. Estes dois parâmetros podem ser melhor compreendidos levando em consideração um gráfico. Seus valores padrão serão definidos como 0, o que marca o centro do gráfico, onde as linhas horizontais e verticais se interceptam. Vamos dar uma olhada em como manipulá-los: + a) Horizontal: Se o valor for positivo e for 2, por exemplo, o centro do Objeto será colocado em uma distância 2 vezes maior do que o tamanho do seu lado Marcador à direita. Se este valor for negativo, digamos -2, será colocado à mesma distância 2 vezes o tamanho do seu lado Marcador para a esquerda. + b) Vertical: Se o valor for positivo e for 2, por exemplo, o centro do objeto será colocado a uma distância 2 vezes maior do que o tamanho do seu lado Marcador, acima dele. Se este valor for negativo, digamos -2, será colocado à mesma distância 2 vezes o tamanho do seu lado Marcador, abaixo dele. + +Depois de ter carregado com sucesso sua imagem e definido seus valores, não se esqueça de dar-lhe um título e dizer se você é seu autor ou não. + +Voilá! Você criou com sucesso seu Objeto e agora pode criar sua Obra Jandig! Lembre-se de que estes dois, Marcador e Objeto, ainda não estão ligados um ao outro. Isto acontecerá na próxima etapa. + +Obras Jandig +~~~~~~~~~~~~~ + +Ok, então agora que já passamos por tudo o que precisávamos para criar uma Obra Jandig, vamos ao processo de criá-la de fato. Uma Obra Jandig é definida pela junção de duas coisas que trabalharão juntas para criar a interação que queremos alcançar. + +Você adivinhou bem, precisaremos fazer uso do Marcador e Objeto criados anteriormente. Nesta seção selecionaremos um Marcador e um Objeto para que a magia possa ser feita e uma Arte AR possa ser vista através da câmera de seu dispositivo. Volte à página principal do Jandig mais uma vez e procure por este botão: + +.. figure:: ../docs/images/artwork-button.png + :scale: 70% + + Botão Create Artwork + +Clique nele e você será redirecionado para uma página que se parece com esta: + +.. figure:: ../docs/images/artwork-page.png + :scale: 60% + + Página de seleção de Marcador e Objeto + + +O processo é simples e direto e praticamente o mesmo para ambos os itens. Você será saudado por um pop-up com muitos Marcadores e Objetos no caso deles, ou nenhum. No caso deste manual ExampleUser, todos os Marcadores e Objetos do caso de teste apareceram. + +Basta selecionar um Marcador, aceitar os termos e pressionar ao lado para selecionar um Objeto. Aqui está um exemplo de Marcador e Objeto selecionados: + +.. figure:: ../docs/images/select-marker.png + :scale: 50% + + Página de seleção de Marcador + +.. figure:: ../docs/images/select-object.png + :scale: 50% + + Página de seleção de objeto + +Dê um título e uma descrição e pronto! + +.. figure:: ../docs/images/finish-art.png + :scale: 50% + + Descrição sobre a Obra + +Voilá! Você criou com sucesso sua primeira Obra Jandig e está quase terminando com este manual! + + +Exposições +~~~~~~~~~~~~ + +Bem-vindo ao último passo! Nesta fase final, mostraremos a você como expor sua arte para o mundo, utilizando o processo de criação de uma Exposição. É através das exposições que o público geral, o qual inclui usuários comuns e até artistas, terá acesso e poderá interagir com suas Obras. + +Para começar, basta acessar o ícone "Create Exhibition" (Criar Exposição). + +.. figure:: ../docs/images/exhibition-main-page.png + :scale: 30% + :target: https://jandig.app/users/exhibits/create/ + + Ícone da página de criação de Exposição + +A seguir, você precisa confirmar que deseja selecionar Obras da coleção. + +.. figure:: ../docs/images/exhibition-select-artwork-button.png + :scale: 30% + :target: https://jandig.app/users/exhibits/create/ + + Botão Select Artwork + + +Entre as Obras da coleção, procure e selecione uma ou mais que você deseja expor. + +.. figure:: ../docs/images/exhibition-select-artwork.png + :scale: 30% + + Selecione Obras da sua coleção + +Após selecionar uma ou mais Obras, dê um título à sua Exposição e defina sua URL. Esta URL será usada para acessar o conjunto de Obras selecionadas para sua exposição. Por exemplo, se você inserir "expos", a URL definitiva para acessar sua criação será "https://jandig.app/expos". + +.. figure:: ../docs/images/exhibition-details.png + :scale: 30% + + Página de detalhes sobre sua Exposição + + +Acesse a URL final que você acabou de criar, aponte a câmera para o Marcador e veja a mágica acontecer! + +Você pode ver todas as suas Exposições no menu "My stuff". E você também pode acessar diretamente de lá, clicando em "Veja esta Exposição". + +... figura:: ../docs/images/exhibition-created.png + escala: 30% + + Página criada da Exposição + +E é isso! Se você chegou a este passo, você criou e exibiu com sucesso suas próprias Obras Jandig em AR para o mundo. Parabéns por ter chegado até aqui, e aproveite todas as experiências que o Jandig tem a oferecer! \ No newline at end of file diff --git a/docs/publicando-obras.rst b/docs/publicando-obras.rst deleted file mode 100644 index 31ab4cc5..00000000 --- a/docs/publicando-obras.rst +++ /dev/null @@ -1,32 +0,0 @@ -Como publicar conteúdo em realidade aumentada no Jandig -======================================================= - -1) Acesse "https://jandig.app/generator". Faça upload da imagem a - ser utilizada no Marcador sem a borda preta (ela será adicionada pelo - aplicativo). Baixe o Marcador (Download .PATT Marker) e a imagem - (Download image Marker) e guarde os arquivos em um local seguro. Se - quiser, baixe PDFs com os marcadores para impressão. Importante: - colocar o Patern Ratio como 0.60. - -2) Acesse "http://jandig.art" e crie uma conta. - -3) Clique em "Enviar Marcador" e suba a imagem (com extensão ".PNG") e - marcador (".PATT") criadas na etapa anterior. Esta imagem é a que a - câmera do Jandig reconhecerá. - -4) Clique em "Enviar Objeto" e faça upload do GIF com a sua animação. - Esta imagem o Jandig exibirá sobre a da câmera. - -5) Clique em "Criar Obra jandig", escolha o Marcador e Objeto - correspondente que você acabou de subir. Uma OBRA é o conjunto do - Marcador e Objeto, vinculando para ser apresentado em realidade - aumentada. - -6) Clique em "Criar Exposição". Escolha uma ou várias obras. Dê um - título para o conjunto e defina sua URL. Ela será usada para acessar - o conjunto de Obras criado por você. Por exemplo, se você inserir - "expoteste" a URL definitiva para acessar sua(s) criações será - "https://jandig.app/expoteste". - -Acesse a URL definitiva que você acabou de criar, aponte a câmera para -o Marcador e veja a mágica acontecer! diff --git a/docs/vision-document.md b/docs/vision-document.md new file mode 100644 index 00000000..b39a40e4 --- /dev/null +++ b/docs/vision-document.md @@ -0,0 +1,116 @@ +# 1. Introduction + +This vision document aims to present the project in its context of existence, as well as an overview of some aspects of the product in order to understand its objectives, opportunities, problems that it aims to solve and other related issues. + +This document is a contribution from students allocated to the Jandig group in the discipline of Software Configuration and Evolution Management, from the Software Engineering course of the first semester of 2020 at the University of Brasília, Campus Gama. + +## 1.1. Scope + +This project aims to develop a responsive web application in order to create works of art with Augmented Reality (AR) technology, aiming to make it possible to hold Exhibitions of such arts, in order to reach a different audience and with a more technological look, in addition to making you an active participant in the creation of artistic elements. + +The project invites the public to transcend the common Exhibition space, so that it can be viewed in a range of media, as long as the basic requirements are met. + +## 1.2 Definitions, acronyms and abbreviations +The definitions, acronyms and abbreviations of the terms used in this document will be listed in this topic, in order to facilitate the understanding of the public interested in the project. + +# 2. Positioning +## 2.1 Business opportunity + +The opportunity was identified to unite artists and the public in Exhibitions in a more simplified way through the application of augmented reality Jandig ARte. With this, artists can publish content through bookmarks and the public, with a camera device, can make their reading animated directly on the screen of their smartphone. + +This application contributes to social events, fosters culture, attracts users and gives them autonomy to disseminate their content in a fun way with augmented reality. + +## 2.2 Problem description + +| The problem is | that affects | whose impact is | a successful solution would include | +| -------- | -------- | -------- | -------- | +| The difficulty in centralizing the dissemination of content by augmented reality | users, both artists and the public | the possible departure from this form of interaction between artist and audience | user engagement to publish and read augmented reality content right from an application | + +## 2.3 Description of product position + +The product can position itself as an easy-to-use online platform capable of engaging users, both artists and audiences, at events and Exhibitions. In addition to being an attractive way to disseminate and show content, it can be used as a vehicle for various information. + +## 3. Users description and their needs + +## 3.1 Envolved parties summary + +| Name | Description | Responsibilities | +| --- | --- | --- | +| memeLab | Laboratory for unstable media (company) | Creator of the product known as Jandig, as well as being one of its stakeholders | +| LabArteMidia - USP | Laboratório de Arte, Mídia e Tecnologias Digitais - University of Sao Paulo | Stakeholder for software development and content creation | +| Developers | Collaborators | Plan, design, prototype, develop, release and maintain Jandig | + +## 3.2 Users description + +| Name | Description | +| -------- | -------- | +| Artists | Professionals or laymen who wish to publish their works | +| Public | Art or technology lovers who want to see Artworks in different media, as well as co-create others, beyond the general public who want to interact with these Artworks through technology | + +## 3.3 Main User Needs + +| User | Needs | Proposed solution | +| -------- | -------- | -------- | +| Artist | Post and publicize your animated Artworks | PWA Application that allows adding and making material available to the public, in the form of Markers and animations | +| Public | Interact with bookmarks and read animations in augmented reality | Reading and interaction of ArtworkS through a PWA application | + +## 3.4 User Environment +Users can fully use the application through browsers on their mobile devices, using the camera. + +## 3.5 Users profiles + +### 3.5.1 Artists + +| Representatives | Type | Responsibility | Sucess Criteria | Involvement| +| - | - | - | - | - | +| Artists | Artistic community (includes independent artists, studios, organizations) | Produce art pieces that can be scanned by Jandig, disseminating theis pieces | Being able to utilize Jandig as a tool for AR-based Exhibitions | High | + +### 3.5.2 Public + +| Representatives | Type | Responsibility | Sucess Criteria | Involvement| +| - | - | - | - | - | +| Art viewers and appreciators | Art enthusiasts and other appreciators that would like to access their favorite pieces in a different manner | Appreciate and disseminate art pieces created using the Jandig tool | Viewing and interacting with Exhibitions and pieces | Medium | + +# 4. Product overview + +## 4.1 Product perspective + +The Jandig initiative aims to bring about a new way of artcrafting, by means of using Augmented Reality technology as a displaying method, one that can be interacted with, with some limitations. + +By enabling artists to create AR pieces, Jandig paves way for art to be less restricted to physical Exhibitions and/or museuns, but at the same time not excluding any of them. Jandig pieces can be attached to many surfaces, in which the user can simply open its website and read the specific piece to be able to see more of its contents. + +Jandig also enable users to create their own Artworks and Exhibitions, following the same methods that professional artists use to create their Artworks on this platform. By doing so, art can become a subject that is less tied to professional artists, and more to the non-professional public. + +## 4.2 Capabilities summary + +| Benefits to the user | Support features | +| - | - | +| Ease of creating augmented reality Artworks | The application allows users and artists to create their art by providing an image and a .gif or video. The system will then provide the steps and other files and configurations that are required to create Artworks and Exhibitions. | +| Ease of viewing and interacting with Exhibitions | For the system to work and for the public to be able to use it, a smartphone with internet access and a camera are required. The user will connect to the platform through its specific URL and will be prompted by a page that asks to fire up the camera. By doing so and by selecting the Exhibition that is tied to the Artwork, users can then see through their smartphones camera the animation or video that is played in a loop.| + +## 4.3 Assumptions and dependencies + +- The user needs to have access to a smartphone with a built-in camera and internet access. + +- The responsive web app will be utilized by people that desire to see AR Artworks that were made within the app requirements. + +# 5. Product requirements + +| Identifier | Requirements | +| - | - | +| RF01 | Allow the user to create, edit, delete their account and log out | +| RF02 | Allow the user to recover their password | +| RF03 | Allow the user to choose the language option between English and Portuguese | +| RF04 | Allow the artist to upload an image to be used as a Marker on the platform | +| RF05 | Allow the artist to upload a Marker to the platform and allow it to be edited | +| RF06 | Allow the artist to upload an Object to the platform and allow it to be edited | +| RF07 | Allow the artist to create a Jandig Artwork | +| RF08 | Allow the artist to delete and edit a Artwork of his own | +| RF09 | Allow the artist to create a digital Exhibition | +| RF10 | Allow the artist to delete and edit an Exhibition of his own | +| RF11 | Allow the artist to see their own Markers, Objects, Artworks and Exhibitions | +| RF12 | Allow the artist to download your Markers, Objects, Artwork and Exhibitions | +| RF13 | Allow the user to see the entire collection of Objects, Markers, Artwork and Exhibitions published by anyone and also download any item in the collection | +| RF14 | Provide a space with tips for the user to learn more about the platform's operation, and allow them to search for some content by keywords | +| RF15 | Allow the user to choose which Exhibition they want to interact with | +| RF16 | Allow the user (with optional login) to interact with Exhibitions using the camera on a mobile device | diff --git a/locustfile.py b/locustfile.py index 9cc3335c..71cc28de 100644 --- a/locustfile.py +++ b/locustfile.py @@ -12,12 +12,6 @@ def exhibit(l): class UserBehavior(TaskSet): tasks = {exhibit:1} - # def on_start(self): - # login(self) - - # def on_stop(self): - # logout(self) - class WebsiteUser(HttpLocust): task_set = UserBehavior wait_time = between(3,5) \ No newline at end of file diff --git a/makefile.py b/makefile.py index 79b30161..63cba821 100644 --- a/makefile.py +++ b/makefile.py @@ -11,8 +11,6 @@ def job(): print("backup done") -# schedule.every(60).seconds.do(job) - schedule.every().day.at("22:00").do(job) while 1: diff --git a/src/ARte/config/settings.py b/src/ARte/config/settings.py index b3a921dd..e09ef1dc 100644 --- a/src/ARte/config/settings.py +++ b/src/ARte/config/settings.py @@ -177,4 +177,4 @@ def debug(request): LOGOUT_REDIRECT_URL = 'home' # Sphinx docs -DOCS_ROOT = os.path.join('../../', 'build/') \ No newline at end of file +DOCS_ROOT = os.path.join(BASE_DIR, '../../build/') \ No newline at end of file diff --git a/src/ARte/core/jinja2/core/arviewer.jinja2 b/src/ARte/core/jinja2/core/arviewer.jinja2 index 9c49a41e..58187c8a 100644 --- a/src/ARte/core/jinja2/core/arviewer.jinja2 +++ b/src/ARte/core/jinja2/core/arviewer.jinja2 @@ -20,16 +20,12 @@ - + - {# #} - {# #} - {# #} - {# #} {% if content is defined %} @@ -45,6 +41,5 @@ {% endif %} {% endblock %} {% endif %} - {# #} \ No newline at end of file diff --git a/src/ARte/core/jinja2/core/base.jinja2 b/src/ARte/core/jinja2/core/base.jinja2 index 94159956..67140115 100644 --- a/src/ARte/core/jinja2/core/base.jinja2 +++ b/src/ARte/core/jinja2/core/base.jinja2 @@ -21,7 +21,7 @@ - + Jandig ARte @@ -46,7 +46,5 @@ {% endblock %} {% endif %} {% include "core/ui.jinja2" %} - {# #} - {# #} \ No newline at end of file diff --git a/src/ARte/core/jinja2/core/collection.jinja2 b/src/ARte/core/jinja2/core/collection.jinja2 index 12f08853..e39c7317 100644 --- a/src/ARte/core/jinja2/core/collection.jinja2 +++ b/src/ARte/core/jinja2/core/collection.jinja2 @@ -8,7 +8,7 @@ {# FIXME: maybe this can be improved #} - + {% if exhibits %}

{{_("Jandig Exhibitions")}}

{% with repository_list = exhibits, element_type="exhibit"%} @@ -18,7 +18,7 @@ {{_("All Exhibits")}} {% endif %} {% endif %} - + {% if artworks %}

{{_("Jandig Artworks")}}

{% with repository_list = artworks, element_type="artwork" %} @@ -28,7 +28,7 @@ {{_("All Artworks")}} {% endif %} {% endif %} - + {% if markers %}

{{_("Jandig Markers")}}

{% with repository_list = markers, element_type="marker"%} @@ -38,7 +38,7 @@ {{_("All Markers")}} {% endif %} {% endif %} - + {% if objects %}

{{_("Jandig Objects")}}

{% with repository_list = objects, element_type="object" %} diff --git a/src/ARte/core/jinja2/core/community.jinja2 b/src/ARte/core/jinja2/core/community.jinja2 index 367dff38..2a987e54 100644 --- a/src/ARte/core/jinja2/core/community.jinja2 +++ b/src/ARte/core/jinja2/core/community.jinja2 @@ -26,5 +26,5 @@

As bordas são os elementos gráficos que engatilham o reconhecimento do objeto associado a cada marcador. Por esse motivo, não se deve cobri-las e elas devem sempre ser vistas completamente pela câmera. Colocar o dedo sobre uma das bordas ou aproximar demais a câmera do marcador inviabiliza o reconhecimento, por exemplo. Essa característica deve sempre ser levada em consideração na produção e aplicação dos marcadores.

- + {% endblock %} \ No newline at end of file diff --git a/src/ARte/core/jinja2/core/community2.jinja2 b/src/ARte/core/jinja2/core/community2.jinja2 deleted file mode 100644 index 3d37de65..00000000 --- a/src/ARte/core/jinja2/core/community2.jinja2 +++ /dev/null @@ -1,36 +0,0 @@ -{% extends 'core/home.jinja2' %} - -{% block community %} -
-
-

Heading 1

-
Fusce a bibendum ante, sit amet luctus est. Praesent sit amet ullamcorper velit. Donec orci nisl, sagittis nec rhoncus vitae.
-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut lorem enim, euismod a velit ut, congue tincidunt lacus. Nunc id dui eu leo blandit sodales non id odio. Nulla ut ante vitae tortor gravida efficitur vitae nec arcu. Integer id fringilla eros. Suspendisse porta feugiat tempor. Aenean eu turpis vitae mi euismod vestibulum. Duis ullamcorper suscipit arcu, at accumsan metus dignissim eu. Ut pellentesque pellentesque tincidunt.

-

Heading 2

-

Proin lacinia augue id ex pretium finibus. Donec egestas euismod tortor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed aliquet convallis ante, at sodales odio egestas pretium. Fusce id fermentum quam. Curabitur vitae ante porta, pharetra metus vitae, vestibulum erat. Morbi eu pellentesque diam. Sed lobortis ultricies viverra. Fusce tempus neque ut orci posuere euismod. Sed vel lacus fermentum, maximus metus sit amet, varius urna.

-

Heading 3

-

Etiam leo neque, gravida non nisl nec, tempus aliquam velit. In ut sagittis erat. Aliquam sit amet pretium urna. Mauris rhoncus nulla quis ligula maximus vehicula. Nullam iaculis purus ultrices leo bibendum ultrices. Donec urna quam, gravida vitae molestie nec, malesuada id risus.

-

Heading 3

-

Nunc gravida, nulla vitae vestibulum eleifend, magna est accumsan massa, consectetur semper metus massa vel nunc. Suspendisse nec urna eu nulla mattis laoreet. Vestibulum tincidunt sit amet orci at maximus. Mauris risus massa, elementum interdum eros ut, porttitor volutpat neque. Quisque gravida convallis ipsum, in pharetra nulla aliquam vitae.

-
    -
  • Fusce a bibendum ante, sit amet luctus est.
  • -
  • Praesent sit amet ullamcorper velit.
  • -
  • Donec orci nisl, sagittis nec rhoncus vitae.
  • -
-

Heading 4

-

Maecenas varius urna at justo accumsan ullamcorper. Nullam dapibus posuere efficitur. Nulla venenatis mi sit amet quam blandit, nec scelerisque turpis tempus. Sed luctus sit amet eros placerat porttitor. Mauris eu convallis nibh.

-
-

Aenean diam magna, porta nec dui eu, pellentesque accumsan orci. Cras id sodales magna, eu eleifend lectus. Nulla facilisi. Ut orci libero, finibus eget faucibus nec, ullamcorper ac quam. Sed semper, nisi vitae tempus vehicula, orci erat euismod metus, vitae lobortis lacus mauris sit amet purus.

-
Heading 5
-

Etiam interdum tortor rhoncus, efficitur diam pretium, tristique orci. Fusce non sapien nec ligula lacinia rhoncus nec ac risus. Etiam efficitur ultricies ante. Nunc vitae eleifend felis. Phasellus posuere augue dolor, quis consequat dui mollis imperdiet. Proin quis fringilla lorem. Praesent pellentesque ac felis vel placerat. Mauris ac mauris sed lectus efficitur pulvinar. Nulla facilisi. Mauris bibendum urna ac ultrices aliquet.

-
    -
  1. Fusce a bibendum ante, sit amet luctus est.
  2. -
  3. Praesent sit amet ullamcorper velit.
  4. -
  5. Donec orci nisl, sagittis nec rhoncus vitae.
  6. -
-
Heading 6
-

Fusce a bibendum ante, sit amet luctus est. Praesent sit amet ullamcorper velit. Donec orci nisl, sagittis nec rhoncus vitae, iaculis et lacus. Sed cursus ligula non nunc interdum, a efficitur purus gravida. Aliquam ullamcorper pharetra libero commodo gravida. Curabitur eget arcu dictum, accumsan nulla sed, gravida ligula. Aliquam turpis lectus, semper eget justo at, fringilla iaculis turpis. In tincidunt quis leo ut interdum. Nulla tellus dolor, euismod nec ipsum et, viverra varius dolor.

- -
-
-{% endblock %} \ No newline at end of file diff --git a/src/ARte/core/jinja2/core/exhibit.jinja2 b/src/ARte/core/jinja2/core/exhibit.jinja2 index 47af81f0..98345aa0 100644 --- a/src/ARte/core/jinja2/core/exhibit.jinja2 +++ b/src/ARte/core/jinja2/core/exhibit.jinja2 @@ -15,12 +15,12 @@ } } - + {% for artwork in artworks %} - @@ -68,7 +68,7 @@ console.log(response) }) }) - + let website = await axios.get(window.location.href) document.getElementById('loadingGif').style.display = 'flex' await requestURLS(1) diff --git a/src/ARte/core/jinja2/core/exhibit_detail.jinja2 b/src/ARte/core/jinja2/core/exhibit_detail.jinja2 index 443084ce..488044a9 100644 --- a/src/ARte/core/jinja2/core/exhibit_detail.jinja2 +++ b/src/ARte/core/jinja2/core/exhibit_detail.jinja2 @@ -2,20 +2,17 @@ {% block content %} - {# #}
-
- {# #} +

{{exhibit.name}}

https://jandig.app/{{exhibit.slug}}

{{_("Created by ")}} {{exhibit.owner.user.username}}

{{ _("See this exhibition") }} - {#

{{exhibit.artworks_count}} {{_("Artworks)}} | {{_("Published on"}} {{exhibit.date}}

#} -
+

{{_("Exhibition Artworks")}}

{% with repository_list = artworks, element_type="artwork" %} {% include "users/components/item-list.jinja2" %} - + {% endwith %} {% include "users/components/elements-modal.jinja2" %} diff --git a/src/ARte/core/jinja2/core/exhibit_select.jinja2 b/src/ARte/core/jinja2/core/exhibit_select.jinja2 index caa51f81..5ae6fa72 100644 --- a/src/ARte/core/jinja2/core/exhibit_select.jinja2 +++ b/src/ARte/core/jinja2/core/exhibit_select.jinja2 @@ -3,6 +3,8 @@ {% block content %} {# FIXME: maybe this can be improved #} + + {% endblock notwelcome %} \ No newline at end of file diff --git a/src/ARte/users/jinja2/users/profile-edit.jinja2 b/src/ARte/users/jinja2/users/profile-edit.jinja2 index 4afc0fca..275d104d 100644 --- a/src/ARte/users/jinja2/users/profile-edit.jinja2 +++ b/src/ARte/users/jinja2/users/profile-edit.jinja2 @@ -9,7 +9,7 @@
- {{ csrf_input }} + {{ csrf_input }} {% for field in form_password.visible_fields() %}

{{ field }} @@ -21,7 +21,7 @@

- {{ csrf_input }} + {{ csrf_input }} {% for field in form_profile.visible_fields() %}

{{ field }} diff --git a/src/ARte/users/jinja2/users/profile.jinja2 b/src/ARte/users/jinja2/users/profile.jinja2 index b2f38ebf..670fac48 100644 --- a/src/ARte/users/jinja2/users/profile.jinja2 +++ b/src/ARte/users/jinja2/users/profile.jinja2 @@ -7,7 +7,7 @@

{% include "users/components/userbox.jinja2" %} - + {# FIXME: maybe this can be improved #} @@ -33,11 +33,11 @@

{{_("You have no Artworks. :c")}}

{{ _('Create one') }} -
+ {% endif %}

{{_("Your Markers")}}

{% if markers %} - {% with deletable=True, repository_list = markers, element_type="marker"%} + {% with deletable=True, editable=True, repository_list = markers, element_type="marker"%} {% include "users/components/item-list.jinja2" %} {% endwith %} {% else %} diff --git a/src/ARte/users/jinja2/users/upload.jinja2 b/src/ARte/users/jinja2/users/upload.jinja2 index b312f528..5bd0e825 100644 --- a/src/ARte/users/jinja2/users/upload.jinja2 +++ b/src/ARte/users/jinja2/users/upload.jinja2 @@ -22,21 +22,21 @@

{{_("Choose Object's title")}} {{ form.visible_fields()[2] }} {{ form.visible_fields()[2].errors }} -

+

{% endif %}

{%if route == 'object-upload' %}

{{_("Choose Object")}}

{% else %}
- No Marker files yet? Don't fret! You can get them - here. + No Marker files yet? Don't fret! You can get them here +

{{_("Choose Marker's title")}} {{ form.visible_fields()[2] }} {{ form.visible_fields()[2].errors }} -

+

{{ _("Choose Marker image") }}

{% endif %} {{ form.visible_fields()[0] }} @@ -62,7 +62,7 @@

Horizontal:

Vertical:

- + {{ form.hidden_fields()[0] }} {{ form.hidden_fields()[0].errors }} @@ -88,7 +88,7 @@ {% elif form_type == 'object' %} {{ _("I'm this Object author") }} {% endif %} - +

{{ form.visible_fields()[1] }} @@ -99,7 +99,7 @@ {{ _('I agree to have this content under CC BY-SA 4.0 and I\'m aware that it can\'t be removed after other people are using it.') }}

-
+
@@ -128,27 +128,50 @@ }); $("#id_source").change( - function(e) { - for (var i = 0; i < e.originalEvent.srcElement.files.length; i++) { - var file = e.originalEvent.srcElement.files[i]; - - var image_preview = document.createElement("img"); - var reader = new FileReader(); - reader.onloadend = function() { + function(e) { + var file = e.originalEvent.srcElement.files[0]; + var image_preview = null; + var previewAndLoadFile = null; + var content_box = document.createElement("div"); + content_box.id = "content-box"; + if (file.type === "video/mp4" || file.type === "video/webm") { + image_preview = document.createElement("video"); + previewAndLoadFile = function() { image_preview.src = reader.result; image_preview.id = "img-preview"; - image_preview.hidden = "hidden"; + image_preview.controls = "controls"; + image_preview.autoplay = "autoplay"; + image_preview.muted = "muted"; + document.getElementById("id_source").after(content_box); + document.getElementById("content-box").appendChild(image_preview); //make preview image of the object/marker show } - reader.readAsDataURL(file); - $("input").after(image_preview); //make preview image of the object/marker show - } + } else { + image_preview = document.createElement("img"); + previewAndLoadFile = function() { + image_preview.src = reader.result; + image_preview.id = "img-preview"; + document.getElementById("id_source").after(content_box); + document.getElementById("content-box").appendChild(image_preview); //make preview image of the object/marker show + } + } + + var reader = new FileReader(); + reader.onloadend = previewAndLoadFile; + reader.readAsDataURL(file); } ); function updateValues(){ var image_preview = document.querySelector('#img-preview'); - var high = image_preview.naturalHeight; - var wide = image_preview.naturalWidth; + var high = null; + var wide = null; + if (image_preview.tagName == "IMG") { + high = image_preview.naturalHeight; + wide = image_preview.naturalWidth; + } else { + high = image_preview.videoHeight; + wide = image_preview.videoWidth; + } if(high >= wide){ var yprop = 1 @@ -164,13 +187,13 @@ var scl = scal*xprop + " " + scal*yprop; var rot = "270 0 0"; var pos = xpos + " " + ypos + " 0"; //messing with the Z gives some really weird things - - $('#id_scale').val(scl); + + $('#id_scale').val(scl); $('#id_rotation').val(rot); $('#id_position').val(pos); } - + {% endblock %} \ No newline at end of file diff --git a/src/ARte/users/models.py b/src/ARte/users/models.py index 1c4b55f4..4a7ae824 100644 --- a/src/ARte/users/models.py +++ b/src/ARte/users/models.py @@ -12,7 +12,7 @@ class Profile(models.Model): bio = models.TextField(max_length=500, blank=True) country = models.CharField(max_length=2, choices=COUNTRY_CHOICES, blank=True) personal_site = models.URLField() - + class Meta: permissions = [ ("moderator", "Can moderate content"), @@ -102,45 +102,72 @@ def in_use(self): return True return False - + @property def xproportion(self): + ''' + The 'xproportion' method is used to always reduce scale + to 1:[something], so that new calculations can be made + when a new scale value is entered by the user. + ''' a = re.findall(r'[\d\.\d]+', self.scale) width = float(a[0]) height = float(a[1]) - if width > 1 : - height = height*1.0/width + if width > height : + height = (height*1.0)/width width = 1 - elif height > 1 : - width = width*1.0/height + else : + width = (width*1.0)/height height = 1 return width @property def yproportion(self): + ''' + The 'yproportion' method is used to always reduce scale + to 1:[something], so that new calculations can be made + when a new scale value is entered by the user. + ''' a = re.findall(r'[\d\.\d]+', self.scale) width = float(a[0]) height = float(a[1]) - if width > 1 : - height = height*1.0/width + if width > height : + height = (height*1.0)/width width = 1 - elif height > 1 : - width = width*1.0/height + else : + width = (width*1.0)/height height = 1 return height @property def xscale(self): + ''' + The 'xscale' method returns the original proportion + of the Object multiplied by the scale value entered + by the user, and thus the Object appears resized in + augmented reality. + ''' a = re.findall(r'[\d\.\d]+', self.scale) return a[0] @property def yscale(self): + ''' + The 'yscale' method returns the original proportion + of the Object multiplied by the scale value entered + by the user, and thus the Object appears resized in + augmented reality. + ''' a = re.findall(r'[\d\.\d]+', self.scale) return a[1] @property def fullscale(self): + ''' + The 'fullscale' method is a workaround to show the + users the last scale value entered by them, when + they attempt to edit it. + ''' x = self.xscale y = self.yscale if x > y: @@ -183,7 +210,7 @@ def exhibits_count(self): def exhibits_list(self): from core.models import Exhibit return list(Exhibit.objects.filter(artworks__in=[self])) - + @property def in_use(self): if self.exhibits_count > 0: diff --git a/src/ARte/users/services/__init__.py b/src/ARte/users/services/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/ARte/users/services/email_service.py b/src/ARte/users/services/email_service.py new file mode 100644 index 00000000..c44aa8ec --- /dev/null +++ b/src/ARte/users/services/email_service.py @@ -0,0 +1,26 @@ +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + + +class EmailService(): + def __init__(self, email_message): + self.jandig_email = "jandig@memelab.com.br" + self.jandig_email_password = "password" + self.email_message = email_message + + def send_email_to_recover_password(self, multipart_message): + email_server = smtplib.SMTP('smtp.gmail.com: 587') + email_server.starttls() + email_server.login(multipart_message['From'], self.jandig_email_password) + email_server.sendmail(multipart_message['From'], multipart_message['To'], multipart_message.as_string()) + email_server.quit() + + def build_multipart_message(self, user_email): + multipart_message = MIMEMultipart() + multipart_message['From'] = self.jandig_email + multipart_message['To'] = '{}'.format(user_email) + multipart_message['Subject'] = "Recover Password" + + multipart_message.attach(MIMEText(self.email_message, 'plain')) + return multipart_message diff --git a/src/ARte/users/services/encrypt_service.py b/src/ARte/users/services/encrypt_service.py new file mode 100644 index 00000000..56d356d8 --- /dev/null +++ b/src/ARte/users/services/encrypt_service.py @@ -0,0 +1,15 @@ +import hashlib +from datetime import datetime + + +class EncryptService(): + def generate_verification_code(self, email): + datetime_now = datetime.now() + today = '{}{}{}{}{}{}{}'.format(datetime_now.year, datetime_now.month, datetime_now.day, datetime_now.hour, datetime_now.minute, datetime_now.second, datetime_now.microsecond) + decrypt_code = str(today) + (email * 4) + verification_code = self.generate_hash_code(decrypt_code) + return verification_code + + def generate_hash_code(self, decrypt_code): + hash_code = hashlib.md5(bytes(decrypt_code, encoding='utf-8')) + return hash_code.hexdigest() \ No newline at end of file diff --git a/src/ARte/users/services/user_service.py b/src/ARte/users/services/user_service.py new file mode 100644 index 00000000..77408755 --- /dev/null +++ b/src/ARte/users/services/user_service.py @@ -0,0 +1,22 @@ +import logging +log = logging.getLogger('ej') + +from django.contrib.auth.models import User + + +class UserService(): + def get_user_email(self, username_or_email): + if '@' in username_or_email: + return username_or_email + user = User.objects.get(username=username_or_email) + log.warning(user) + return user.email + + def check_if_username_or_email_exist(self, username_or_email): + if '@' in username_or_email: + if not User.objects.filter(email=username_or_email).exists(): + return False + else: + if not User.objects.filter(username=username_or_email).exists(): + return False + return True \ No newline at end of file diff --git a/src/ARte/users/static/css/label.css b/src/ARte/users/static/css/label.css new file mode 100644 index 00000000..5a32046b --- /dev/null +++ b/src/ARte/users/static/css/label.css @@ -0,0 +1,33 @@ +.url-helper { + float: left; + width: 35%; + font-weight: bold; +} + +@media screen and (min-width: 601px) { + label.url-helper { + font-size: 15px; + padding-top: 3%; + } + } + + @media screen and (max-width: 600px) { + label.url-helper { + font-size: 12px; + padding-top: 3.2%; + } + } + + @media screen and (max-width: 371px) { + label.url-helper { + font-size: 10px; + padding-top: 5%; + } + } + + @media screen and (max-width: 320px) { + label.url-helper { + font-size: 9px; + padding-top: 6%; + } + } \ No newline at end of file diff --git a/src/ARte/users/static/css/profile.css b/src/ARte/users/static/css/profile.css index 4fce2879..723893c4 100644 --- a/src/ARte/users/static/css/profile.css +++ b/src/ARte/users/static/css/profile.css @@ -83,7 +83,7 @@ .upMrk, .upObj { background-color: #f1f1f1; - font-size: 0.85em; + font-size: 0.85em; flex-basis: calc(50% - 5px); margin: auto 0; height: 40px; @@ -120,7 +120,7 @@ } .createArtwork { - background-color: #cdf0d8; + background-color: #cdf0d8; } .createArtwork a.option-link { @@ -129,7 +129,7 @@ .createExhibition { background-color: #eccdf0; - margin-bottom: 20px; + margin-bottom: 20px; } .createExhibition a.option-link { diff --git a/src/ARte/users/static/css/repository-list.css b/src/ARte/users/static/css/repository-list.css index 54a918de..ec314541 100644 --- a/src/ARte/users/static/css/repository-list.css +++ b/src/ARte/users/static/css/repository-list.css @@ -42,8 +42,8 @@ border: 8px solid #fff; opacity: 1; display: block; - background-size: contain; - margin: 10px 10px -20px auto; + background-size: contain; + margin: 10px 10px -20px auto; } .repository-item a.edit:hover, .repository-item a.delete:hover, .repository-item a.preview:hover { @@ -52,17 +52,17 @@ .repository-item a.edit { background: url(../images/icons/edit.png) no-repeat center center; - background-size: contain; + background-size: contain; } .repository-item a.delete{ background: url(../images/icons/delete.png) no-repeat center center; - background-size: contain; + background-size: contain; } .repository-item a.preview { background: url(../images/icons/preview.png) no-repeat center center; - background-size: contain; + background-size: contain; } #repo-artwork .repository-item { @@ -88,9 +88,12 @@ flex: 0 1 calc(25%); } -#repo-marker .repository-item a.delete, #repo-marker .repository-item a.edit, -#repo-object .repository-item a.delete, #repo-object .repository-item a.edit { - /*margin: 25px 0px -60px -25px;*/ +#repo-marker .repository-item a.delete, #repo-object .repository-item a.delete { + margin: -20px 0 0 85px; + position: absolute; +} + +#repo-marker .repository-item a.edit, #repo-object .repository-item a.edit { margin: -20px 0 -30px 40px; position: absolute; } diff --git a/src/ARte/users/static/css/upload.css b/src/ARte/users/static/css/upload.css index aac77e2d..9bcf1c24 100644 --- a/src/ARte/users/static/css/upload.css +++ b/src/ARte/users/static/css/upload.css @@ -29,7 +29,7 @@ margin: 0; } -#tip1, #tip2 { +#tip1, #tip2 { position: relative; background: rgba(0,0,0,0.85); color: rgb(255, 255, 255); @@ -46,4 +46,26 @@ #positionTitle:hover + #tip2 { display: inline-block; -} \ No newline at end of file +} + +#content-box { + height: 50%; + width: 65%; +} + +img { + max-width: 100%; + max-height: 100%; +} + +video{ + max-width: 100%; + max-height: 100%; +} + +@media only screen and (max-width: 600px){ + #content-box { + height: 60%; + width: 60%; + } +}; \ No newline at end of file diff --git a/src/ARte/users/tests.py b/src/ARte/users/tests.py index 7ce503c2..b2a48585 100644 --- a/src/ARte/users/tests.py +++ b/src/ARte/users/tests.py @@ -1,3 +1,100 @@ -from django.test import TestCase +import factory -# Create your tests here. +from django.test import TestCase, Client, RequestFactory +from unittest import mock +from .views import edit_object, recover_password +from .services.email_service import EmailService +from .services.encrypt_service import EncryptService +from .services.user_service import UserService +from .factory import ObjectFactory, UserFactory + +class UserTestCase(TestCase): + def setUp(self): + self.client_test = RequestFactory() + self.email_service = EmailService('You have requested a new password.') + self.encrypt_service = EncryptService() + self.user_service = UserService() + + request = self.client_test.get('/recover/', follow=True) + def test_redirect_to_recover_password_page(self): + self.assertEqual(response.status_code, 200) + response = recover_password(request) + + def test_recover_password_invalid_email(self): + request = self.client_test.post('/recover/', {'username_or_email': 'testadorinvalid@memelab.com'}, follow=True) + response = recover_password(request) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/users/invalid-recovering-email') + + def test_recover_password_invalid_username(self): + request = self.client_test.post('/recover/', {'username_or_email': 'testadorinvalid'}, follow=True) + response = recover_password(request) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/users/invalid-recovering-email') + + def test_recover_password_valid_email(self): + request = self.client_test.post('/recover/', {'username_or_email': 'testador@memelab.com'}, follow=True) + user_data = UserFactory() + response = recover_password(request) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/users/recover-code/') + + def test_recover_password_valid_username(self): + request = self.client_test.post('/recover/', {'username_or_email': 'Testador'}, follow=True) + user_data = UserFactory() + response = recover_password(request) + self.assertEqual(response.status_code, 302) + self.assertEqual(response.url, '/users/recover-code/') + + def test_build_multipart_message(self): + email = "testador@memelab.com" + response = self.email_service.build_multipart_message(email) + self.assertEquals(response['From'], "jandig@memelab.com.br") + self.assertEquals(response['To'], email) + + @mock.patch('users.services.email_service.smtplib.SMTP.quit') + def test_send_email_to_recover_password(self, mock_quit): + email = "testador@memelab.com" + response = self.email_service.build_multipart_message(email) + self.email_service.send_email_to_recover_password(response) + mock_quit.assert_called_once() + + @mock.patch('users.services.encrypt_service.EncryptService.generate_hash_code') + def test_generate_verification_code(self, mock_hash): + email = "testador@memelab.com" + self.encrypt_service.generate_verification_code(email) + mock_hash.assert_called_once() + + def test_check_if_username_or_email_exist(self): + email = "testador@memelab.com" + user_data = UserFactory() + response = self.user_service.check_if_username_or_email_exist(email) + self.assertTrue(response) + + def test_check_if_username_or_email_doesnt_exist(self): + email = "testadorinvalido@memelab.com" + user_data = UserFactory() + response = self.user_service.check_if_username_or_email_exist(email) + self.assertFalse(response) + + def test_get_user_email_by_email(self): + email = "testador@memelab.com" + user_data = UserFactory() + response = self.user_service.get_user_email(email) + self.assertEquals(response, email) + + def test_get_user_email_by_username(self): + username = "Testador" + user_data = UserFactory() + response = self.user_service.get_user_email(username) + self.assertEquals(response, "testador@memelab.com") + + +class EditObjectTestCase(TestCase): + def setUp(self): + self.client_test = RequestFactory() + + def test_redirect(self): + request = self.client_test.get('objects/edit', follow=True) + response = edit_object(request) + self.assertEqual(response.status_code, 200) \ No newline at end of file diff --git a/src/ARte/users/urls.py b/src/ARte/users/urls.py index 92e27e47..b257a25c 100644 --- a/src/ARte/users/urls.py +++ b/src/ARte/users/urls.py @@ -2,7 +2,7 @@ from django.contrib.auth import views as auth_views from .forms import LoginForm -from .views import download_exhibit, edit_object, signup, recover_password, recover_edit_password, invalid_recovering_email, recover_code, wrong_verification_code, profile, marker_upload, object_upload, create_artwork, create_exhibit, edit_artwork, element_get, edit_exhibit, edit_profile, edit_password, delete, related_content, mod_delete, permission_denied, mod +from .views import download_exhibit, edit_object, edit_marker, signup, recover_password, recover_edit_password, invalid_recovering_email_or_username, recover_code, wrong_verification_code, profile, marker_upload, object_upload, create_artwork, create_exhibit, edit_artwork, element_get, edit_exhibit, edit_profile, edit_password, delete, related_content, mod_delete, permission_denied, mod urlpatterns = [ path('signup/', signup, name='signup'), @@ -18,7 +18,7 @@ path('profile/edit/', edit_profile, name="edit-profile"), path('profile/edit-password/', edit_password, name="edit-password"), path('wrong-verification-code', wrong_verification_code, name="wrong-verification-code"), - path('invalid-recovering-email', invalid_recovering_email, name="invalid-recovering-email"), + path('invalid-recovering-email', invalid_recovering_email_or_username, name="invalid_recovering_email_or_username"), path('recover-edit-password', recover_edit_password, name="recover-edit-password"), path('markers/upload/', marker_upload, name='marker-upload'), @@ -26,10 +26,11 @@ path('element/get/', element_get, name='element-get'), path('objects/edit/', edit_object, name='edit-object'), + path('markers/edit/', edit_marker, name='edit-marker'), path('artworks/create/', create_artwork, name='create-artwork'), path('artworks/edit/', edit_artwork, name="edit-artwork"), - + path('exhibits/create/', create_exhibit, name='create-exhibit'), path('exhibits/edit/', edit_exhibit, name='edit-exhibit'), path('download-exhibit', download_exhibit, name="download-exhibit"), diff --git a/src/ARte/users/views.py b/src/ARte/users/views.py index 6bc7ab9d..f86d7cd4 100644 --- a/src/ARte/users/views.py +++ b/src/ARte/users/views.py @@ -2,9 +2,6 @@ import logging from datetime import datetime import hashlib -import smtplib -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText log = logging.getLogger('ej') from django.contrib.auth import login, authenticate import django.contrib.auth @@ -23,12 +20,15 @@ from .models import Marker, Object, Artwork, Profile from core.models import Exhibit from core.helpers import * +from .services.email_service import EmailService +from .services.user_service import UserService +from .services.encrypt_service import EncryptService def signup(request): if request.method == 'POST': form = SignupForm(request.POST) - + if form.is_valid(): form.save() username = form.cleaned_data.get('username') @@ -47,56 +47,37 @@ def signup(request): def recover_password(request): if request.method == 'POST': - form = RecoverPasswordForm(request.POST) + recover_password_form = RecoverPasswordForm(request.POST) - if form.is_valid(): - username_or_email = form.cleaned_data.get('username_or_email') - global recovering_email - - if '@' in username_or_email: - recovering_email = username_or_email - - if not User.objects.filter(email=recovering_email).exists(): - return redirect('invalid-recovering-email') - - else: - if not User.objects.filter(username=username_or_email).exists(): - return redirect('invalid-recovering-email') - - user = User.objects.get(username=username_or_email) - recovering_email = user.email - log.warning(user) - - now = datetime.now() - today = '{}{}{}{}{}{}{}'.format(now.year, now.month, now.day, now.hour, now.minute, now.second, now.microsecond) - hash_code = str(today) + (recovering_email * 4) - - global verification_code - - verification_code = hashlib.md5(bytes(hash_code, encoding='utf-8')) - verification_code = verification_code.hexdigest() - - msg = MIMEMultipart() - message = 'You have requested a new password. This is your verification code: {}\nCopy it and put into the field.'.format(verification_code) - password = 'svxrhkcftyvhtvyy' - msg['From'] = "jandig@memelab.com.br" - msg['To'] = '{}'.format(recovering_email) - msg['Subject'] = "Recover Password" - - msg.attach(MIMEText(message, 'plain')) - - email_server = smtplib.SMTP('smtp.gmail.com: 587') - email_server.starttls() - email_server.login(msg['From'], password) - email_server.sendmail(msg['From'], msg['To'], msg.as_string()) - email_server.quit() + if recover_password_form.is_valid(): + username_or_email = recover_password_form.cleaned_data.get('username_or_email') + user_service = UserService() + username_or_email_is_valid = user_service.check_if_username_or_email_exist(username_or_email) + if (not username_or_email_is_valid): + return redirect('invalid_recovering_email_or_username') + + global global_recovering_email + global_recovering_email = user_service.get_user_email(username_or_email) + + global global_verification_code + encrypt_service = EncryptService() + global_verification_code = encrypt_service.generate_verification_code(global_recovering_email) + + build_message_and_send_to_user(global_recovering_email) return redirect('recover-code') else: - form = RecoverPasswordForm() + recover_password_form = RecoverPasswordForm() + + return render(request, 'users/recover-password.jinja2', {'form': recover_password_form}) + +def build_message_and_send_to_user(email): + message = 'You have requested a new password. This is your verification code: {}\nCopy it and put into the field.'.format(global_verification_code) + email_service = EmailService(message) + multipart_message = email_service.build_multipart_message(email) + email_service.send_email_to_recover_password(multipart_message) - return render(request, 'users/recover-password.jinja2', {'form': form}) def recover_code(request): if request.method == 'POST': @@ -106,15 +87,15 @@ def recover_code(request): code = form.cleaned_data.get('verification_code') log.warning('Inserido: ' + code) - log.warning('Correto: ' + verification_code) + log.warning('Correto: ' + global_verification_code) - if(code == verification_code): + if(code == global_verification_code): global recover_password_user - recover_password_user = User.objects.get(email=recovering_email) + recover_password_user = User.objects.get(email=global_recovering_email) return redirect('recover-edit-password') else: return redirect('wrong-verification-code') - + return redirect('home') else: form = RecoverPasswordCodeForm() @@ -137,7 +118,7 @@ def recover_edit_password(request): def wrong_verification_code(request): return render(request, 'users/wrong-verification-code.jinja2') -def invalid_recovering_email(request): +def invalid_recovering_email_or_username(request): return render(request, 'users/invalid-recovering-email.jinja2') @@ -149,7 +130,7 @@ def profile(request): markers = profile.marker_set.all() objects = profile.object_set.all() artworks = profile.artwork_set.all() - + ctx = { 'exhibits': exhibits, 'artworks': artworks, @@ -159,45 +140,37 @@ def profile(request): } return render(request, 'users/profile.jinja2', ctx) +@cache_page(60 * 60) +def get_element(request, form, form_class, form_type, source, author, existent_element): + element = None + + if(source and author): + instance = form_type(source=source, author=author) + element = form_class(instance=instance).save(commit=False) + element.save() + elif(existent_element): + qs = form_type.objects.filter(id=existent_element) + if qs: + element = qs[0] + element.owner = request.user.profile + + return element + @cache_page(60 * 60) def get_marker(request, form): marker_src = form.cleaned_data['marker'] marker_author = form.cleaned_data['marker_author'] existent_marker = form.cleaned_data['existent_marker'] - marker = None - - if(marker_src and marker_author): - marker_instance = Marker(source=marker_src, author=marker_author) - marker = UploadMarkerForm(instance=marker_instance).save(commit=False) - marker.owner = request.user.profile - marker.save() - elif(existent_marker): - qs = Marker.objects.filter(id=existent_marker) - if qs: - marker = qs[0] - marker.owner = request.user.profile - return marker + return get_element(request, form, UploadMarkerForm, Marker, source=marker_src, author=marker_author, existent_element=existent_marker) @cache_page(60 * 60) def get_augmented(request, form): object_src = form.cleaned_data['augmented'] object_author = form.cleaned_data['augmented_author'] existent_object = form.cleaned_data['existent_object'] - augmented = None - - if(object_src and object_author): - object_instance = Object(source=object_src, author=object_author) - augmented = UploadObjectForm(instance=object_instance).save(commit=False) - augmented.owner = request.user.profile - augmented.save() - elif(existent_object): - qs = Object.objects.filter(id=existent_object) - if qs: - augmented = qs[0] - augmented.owner = request.user.profile - return augmented + return get_element(request, form, UploadObjectForm, Object, source=object_src, author=object_author, existent_element=existent_object) @login_required def create_artwork(request): @@ -207,8 +180,8 @@ def create_artwork(request): if form.is_valid(): marker = get_marker(request,form) - augmented = get_augmented(request, form) - + augmented = get_augmented(request, form) + if marker and augmented: artwork_title = form.cleaned_data['title'] artwork_desc = form.cleaned_data['description'] @@ -230,14 +203,12 @@ def create_artwork(request): request, 'users/artwork-create.jinja2', { - 'form': form, + 'form': form, 'marker_list': marker_list, 'object_list': object_list, } ) - - @login_required def create_exhibit(request): if request.method == 'POST': @@ -250,7 +221,7 @@ def create_exhibit(request): name=form.cleaned_data['name'], slug=form.cleaned_data['slug'], ) - + exhibit.save() exhibit.artworks.set(artworks) @@ -264,7 +235,7 @@ def create_exhibit(request): request, 'users/exhibit-create.jinja2', { - 'form': form, + 'form': form, 'artworks': artworks, } ) @@ -305,12 +276,9 @@ def download_exhibit(request): } all_data.append(data) - + return HttpResponse(json.dumps(all_data)) -@login_required -def marker_upload(request): - return upload_view(request, UploadMarkerForm, 'marker', 'marker-upload') @cache_page(60 * 2) def element_get(request): @@ -323,7 +291,7 @@ def element_get(request): elif request.GET.get('artwork_id', None): element_type = 'artwork' element = get_object_or_404(Artwork, pk=request.GET['artwork_id']) - + if element_type == 'artwork': data = { 'id_marker' : element.marker.id, @@ -334,6 +302,7 @@ def element_get(request): 'created_at': element.created_at.strftime('%d %b, %Y'), 'marker': element.marker.source.url, 'augmented': element.augmented.source.url, + 'augmented_size': element.augmented.source.size, 'title': element.title, 'description': element.description, } @@ -354,13 +323,7 @@ def element_get(request): return HttpResponse(serialized, content_type='application/json') - -@login_required -def object_upload(request): - return upload_view(request, UploadObjectForm, 'object', 'object-upload') - - -def upload_view(request, form_class, form_type, route): +def upload_elements(request, form_class, form_type, route): if request.method == 'POST': form = form_class(request.POST, request.FILES) if form.is_valid(): @@ -370,30 +333,52 @@ def upload_view(request, form_class, form_type, route): return redirect('home') else: form = form_class() - return render(request,'users/upload.jinja2', - {'form_type': form_type, 'form': form, 'route': route, 'edit': False}) + { + 'form_type': form_type, + 'form': form, + 'route': route, + 'edit': False + } + ) +@login_required +def marker_upload(request): + return upload_elements(request, UploadMarkerForm, 'marker', 'marker-upload') @login_required -def edit_object(request): - id = request.GET.get("id","-1") - model = Object.objects.get(id=id) +def object_upload(request): + return upload_elements(request, UploadObjectForm, 'object', 'object-upload') + +def edit_elements(request, form_class, route, model, model_data): if(not model or model.owner != Profile.objects.get(user=request.user)): raise Http404 if(request.method == "POST"): - form = UploadObjectForm(request.POST, request.FILES, instance = model) + form = form_class(request.POST, request.FILES, instance = model) form.full_clean() if form.is_valid(): - if form.cleaned_data["source"] == None: - form.cleaned_data["source"] == model.source + form.cleaned_data["source"] == model.source form.save() return redirect('profile') else: log.warning(form.errors) + + return render( + request, route, + { + 'form': form_class(initial=model_data), + 'model': model, + } + ) + +@login_required +def edit_object(request): + id = request.GET.get("id", "-1") + model = Object.objects.get(id=id) + model_data = { "source": model.source, "uploaded_at": model.uploaded_at, @@ -403,20 +388,26 @@ def edit_object(request): "rotation": model.rotation, "title": model.title, } + return edit_elements(request, UploadObjectForm, route='users/edit-object.jinja2', model=model, model_data=model_data) - return render( - request, - 'users/edit-object.jinja2', - { - 'form': UploadObjectForm(initial=model_data), - 'model': model, - } - ) +@login_required +def edit_marker(request): + id = request.GET.get("id", "-1") + model = Marker.objects.get(id=id) + + model_data = { + "source": model.source, + "uploaded_at": model.uploaded_at, + "author": model.author, + "patt": model.patt, + "title": model.title, + } + return edit_elements(request, UploadMarkerForm, route='users/edit-marker.jinja2', model=model, model_data=model_data) @login_required -def edit_artwork(request): +def edit_artwork(request): id = request.GET.get("id","-1") model = Artwork.objects.filter(id=id) if(not model or model.first().author != Profile.objects.get(user=request.user)): @@ -453,7 +444,7 @@ def edit_artwork(request): request, 'users/artwork-create.jinja2', { - 'form': ArtworkForm(initial=model_data), + 'form': ArtworkForm(initial=model_data), 'marker_list': Marker.objects.all(), 'object_list': Object.objects.all(), 'selected_marker': model.marker.id, @@ -463,7 +454,7 @@ def edit_artwork(request): @login_required -def edit_exhibit(request): +def edit_exhibit(request): id = request.GET.get("id","-1") model = Exhibit.objects.filter(id=id) if(not model or model.first().owner != Profile.objects.get(user=request.user)): @@ -484,7 +475,7 @@ def edit_exhibit(request): model.update(**model_data) model = model.first() model.artworks.set(artworks) - + return redirect('profile') model = model.first() @@ -505,7 +496,7 @@ def edit_exhibit(request): request, 'users/exhibit-create.jinja2', { - 'form': ExhibitForm(initial=model_data), + 'form': ExhibitForm(initial=model_data), 'artworks': artworks, 'selected_artworks': model_artworks, } @@ -523,7 +514,7 @@ def edit_password(request): else: profile = Profile.objects.get(user=request.user) ctx={ - 'form_password': PasswordChangeForm(request.user), + 'form_password': PasswordChangeForm(request.user), 'form_profile': ProfileForm(instance=profile) } return render(request,'users/profile-edit.jinja2',ctx) @@ -559,7 +550,7 @@ def edit_profile(request): @login_required def delete(request): content_type = request.GET.get('content_type', None) - + if content_type == 'marker': delete_content(Marker, request.user, request.GET.get('id', -1)) elif content_type == 'object': @@ -572,24 +563,44 @@ def delete(request): def delete_content(model, user, instance_id): qs = model.objects.filter(id=instance_id) + if qs: instance = qs[0] - if isinstance(instance, Exhibit) and (instance.owner == user.profile or user.has_perm('users.moderator')): - instance.delete() + if user.has_perm('users.moderator'): + delete_content_Moderator(instance,user) else: - if user.has_perm('users.moderator') and not instance.in_use: + isArtwork = isinstance(instance, Artwork) + if isArtwork: + hasPermission = (instance.author == user.profile) + else: + hasPermission = (instance.owner == user.profile) + + isInstanceSameTypeofModel = isinstance(instance, model) + if isInstanceSameTypeofModel and hasPermission: instance.delete() - elif user.has_perm('users.moderator') and instance.in_use: - if isinstance(instance, Object): - artworkIn = Artwork.objects.filter(augmented=instance) - artworkIn.delete() - instance.delete() - elif isinstance(instance, Marker): - artworkIn = Artwork.objects.filter(marker=instance) - artworkIn.delete() - instance.delete() - elif isinstance(instance, Artwork): - instance.delete() + + +def delete_content_Moderator(instance,user): + + isInstanceSameTypeofModel = isinstance(instance, model) + isObject = isinstance(instance, Object) + isMarker = isinstance(instance, Marker) + isArtwork = isinstance(instance, Artwork) + + + if isInstanceSameTypeofModel or not instance.in_use: + instance.delete() + elif instance.in_use: + if isObject: + artworkIn = Artwork.objects.filter(augmented=instance) + artworkIn.delete() + instance.delete() + elif isMarker: + artworkIn = Artwork.objects.filter(marker=instance) + artworkIn.delete() + instance.delete() + elif isArtwork: + instance.delete() def related_content(request): @@ -607,22 +618,22 @@ def related_content(request): ctx = {'artworks': artworks, 'exhibits': exhibits, "seeall:":False} elif element_type == 'marker': element = Marker.objects.get(id=element_id) - + artworks = element.artworks_list exhibits = element.exhibits_list ctx = {'artworks': artworks, 'exhibits': exhibits, "seeall:":False} elif element_type == 'artwork': element = Artwork.objects.get(id=element_id) - + exhibits = element.exhibits_list - - ctx = {'exhibits': exhibits, "seeall:":False} - + + ctx = {'exhibits': exhibits, "seeall:":False} + return render(request, 'core/collection.jinja2', ctx) @login_required -def mod_delete(request): +def mod_delete(request): content_type = request.GET.get('content_type', None) if content_type == 'marker': delete_content(Marker, request.user, request.GET.get('instance_id', -1)) @@ -642,7 +653,7 @@ def mod(request): "artworks": Artwork.objects.all(), "exhibits": Exhibit.objects.all(), "permission" : request.user.has_perm('users.moderator'), - } + } return render(request, 'users/moderator-page.jinja2', ctx) def permission_denied (request): diff --git a/src/requirements.txt b/src/requirements.txt index be35799f..e1b71abe 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,4 +1,4 @@ -django == 2.2.10 +django == 2.2.13 jinja2 >= 2.10 gunicorn >= 19.0 pillow >= 5.3.0 @@ -11,4 +11,5 @@ sphinx ~= 2.1.1 django-docs ~= 0.3.1 babel ~= 2.7.0 django-debug-toolbar -gevent \ No newline at end of file +gevent +factory_boy \ No newline at end of file