-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/association manager #302
Conversation
…sociation screen if you have any Permission on it
…& create Association member @composable for Actions page
…odel to add a Role locally to reduce fetches from the database
… in UI + do it securely
…n to avoid future errors
Thanks again for your review Oskar ! I implemented everything you asked ; ) |
…rebase emulators data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work, you achieved remarkable code quality given the size of this PR !
# waiting for Arnaud's PR, temporarily commenting this | ||
#- name: Run Node tests with Firestore and Storage emulators | ||
# run: firebase emulators:exec --only firestore,storage 'npm run test' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to uncomment this as soon as we have merged my PR :)
composeTestRule.waitUntil(10000) { | ||
composeTestRule.onNodeWithTag(AssociationProfileTestTags.ACTIONS_PAGE).isDisplayed() | ||
} | ||
composeTestRule.onNodeWithTag(AssociationProfileTestTags.ACTIONS_PAGE).performClick() | ||
|
||
composeTestRule.waitUntil(10000) { | ||
composeTestRule | ||
.onNodeWithTag(AssociationProfileActionsTestTags.ADD_EVENT_BUTTON) | ||
.isDisplayed() | ||
} | ||
|
||
composeTestRule | ||
.onNodeWithTag(AssociationProfileActionsTestTags.ADD_EVENT_BUTTON) | ||
.assertIsDisplayed() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is basic testing but it ensures that everything is well displayed.
@@ -199,14 +199,11 @@ class AccountDetailsTest : TearDown() { | |||
.onNodeWithTag(SocialsOverlayTestTags.SAVE_BUTTON) | |||
.performScrollTo() | |||
.performClick() | |||
Thread.sleep(20000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this was for test reasons, tell me if I'm wrong
fun testEventCardElementsExistEdit() { | ||
setEventViewModel(listOf(sampleEvent)) | ||
setEventScreen(sampleEvent, true) | ||
|
||
Thread.sleep(10000) | ||
composeTestRule | ||
.onNodeWithTag(EventCardTestTags.EVENT_TITLE, useUnmergedTree = true) | ||
.assertExists() | ||
.assertTextEquals("Sample Event") | ||
|
||
composeTestRule | ||
.onNodeWithTag(EventCardTestTags.EVENT_MAIN_TYPE, useUnmergedTree = true) | ||
.assertExists() | ||
.assertTextEquals("Trip") | ||
|
||
composeTestRule | ||
.onNodeWithTag(EventCardTestTags.EVENT_LOCATION, useUnmergedTree = true) | ||
.assertExists() | ||
.assertTextEquals("Sample Location") | ||
|
||
composeTestRule | ||
.onNodeWithTag(EventCardTestTags.EVENT_DATE, useUnmergedTree = true) | ||
.assertExists() | ||
.assertTextEquals("20/07") | ||
|
||
composeTestRule | ||
.onNodeWithTag(EventCardTestTags.EVENT_TIME, useUnmergedTree = true) | ||
.assertExists() | ||
.assertTextEquals("00:00") | ||
|
||
composeTestRule | ||
.onNodeWithTag(EventCardTestTags.EVENT_CATCHY_DESCRIPTION, useUnmergedTree = true) | ||
.assertExists() | ||
.assertTextEquals("This is a catchy description.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to add tests to some old code and not only to the new one ! 🚀
@@ -193,6 +193,7 @@ class EventDetailsTest : TearDown() { | |||
composeTestRule | |||
.onNodeWithTag(EventDetailsTestTags.SHARE_BUTTON) | |||
.assertDisplayComponentInScroll() | |||
Thread.sleep(20000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, this seems like debug instruction
} | ||
|
||
Row( | ||
modifier = Modifier.fillMaxWidth().padding(vertical = 0.dp), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null padding
*/ | ||
@OptIn(ExperimentalMaterial3Api::class) | ||
@Composable | ||
fun <T> SearchBar( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesnt seem to be used anywhere :(
* | ||
* @param T The type of the entity (e.g., Event, Member, Association). | ||
* @param items The list of items to display in the pager. | ||
* @param searchViewModel The view model handling the search logic. | ||
* @param onItemSelected Callback when an item is selected from search results. | ||
* @param cardContent A composable lambda that defines how to render each pager content. | ||
* @param title The title displayed above the section. | ||
* @param searchBar Composable function for rendering the search bar. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
javadoc to update
// Sliding Progress Bar (if more than one item exists) | ||
if (items.size > 1) { | ||
// Search Bar Composable | ||
// Box(modifier = Modifier.fillMaxWidth().padding(horizontal = 20.dp)) { searchBar() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented code
Box( | ||
modifier = | ||
Modifier.fillMaxSize().drawBehind { | ||
val totalWidth = sizeList.values.map { it.first }.sum() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused variable
Quality Gate failedFailed conditions |
This PR aims to completely deploy the association permissions into the UI.
That means that the user is now able to :
Cool implementations :
When creating/editing a role, I thought a Color Picker is better than giving a HEX code or a Long. I found this superb Color Picker on github by SkyDoves - it's even compatible with Kotlin Multiplatform ! Good to know when we'll want to implement Swift.
Now Roles are only in the Association.roles and not copied in Association.members.role to avoid differences in the memory and better data optimization
Security measures :
Create and editing an association is now managed by cloud functions. That means that you don't directly perform the operations to the db - you just call a cloud function to check your permissions (and by that I mean the permissions of your roles) and proceed if you have at least "Add & Edit Association"
Cloud functions are now more safe : before, to know who's calling the function the userId was given as a string parameter. This is a dangerous security hole : as the uid of the users in the db is the same as the one visible in the Association dataclass, that means that everyone can know the uid of his comrade and thus give it the the cloud function instead of its own. Now, your userID is tokenized (only an authentificated user can have its own token) and then send to the cloud function which detokenize it to fall back on the userUid : ) If you think this is not the best way to proceed, maybe first read the documentation, it's right here - other possibilities are explained here.
Fixes :
Questions :
saveEvent
cloud function you might ask why I send the Firebase Timestamp as a string. It's because there's no way to pass it via a json Object which is the type used for the parameters of the cloud functions. So the solution is to format all the informations in a string in Kotlin and then rebuild the Timestamp in javascript.