Skip to content
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

[Bug] Google Classroom function bug collection #87

Closed
4 tasks done
scrthq opened this issue Oct 2, 2018 · 73 comments
Closed
4 tasks done

[Bug] Google Classroom function bug collection #87

scrthq opened this issue Oct 2, 2018 · 73 comments
Assignees
Labels

Comments

@scrthq
Copy link
Member

scrthq commented Oct 2, 2018

Current bugs with Google Classroom specific functions and their status:

@scrthq scrthq added the bug label Oct 2, 2018
@scrthq scrthq self-assigned this Oct 2, 2018
@scrthq
Copy link
Member Author

scrthq commented Oct 2, 2018

@IronKane2 - Tracking issues here

@scrthq
Copy link
Member Author

scrthq commented Oct 2, 2018

For item 2, it looks like the Classroom API balks when trying to submit the request to list Courses in all of the valid CourseStates, which is why it was failing; default value is set to request all CourseStates, that has been removed in Dev. Also tested different combinations of CourseStates and here are the following that work:

  • ACTIVE,DECLINED (either together or by themselves)
  • ARCHIVED (by itself)
  • PROVISIONED (by itself)
  • SUSPENDED (by itself)
  • COURSESTATEUNSPECIFIED (by itself)

For item 3, the calls to Add-Member have been removed from Get-GSCourseParticipant in Dev. Shouldn't have that issue once 2.14.1 comes out shortly.

scrthq added a commit that referenced this issue Oct 2, 2018
## 2.14.1

* [Issue #87](#87)
  * Removed `Add-Member` calls from `Get-GSCourseParticipant` to resolve item 3 on issue
  * Cleaned up `CourseStates` parameter on `Get-GSCourse` to validate against the Enum directly and removed the default parameter value to resolve item 2 on issue
  * Cleaned up `State` parameter on `Get-GSStudentGuardianInvitation` to validate against the Enum directly in an effort to prevent the same issue as item 2
@scrthq
Copy link
Member Author

scrthq commented Oct 2, 2018

@IronKane2 - PSGSuite v2.14.1 is available now on the Gallery with fixes for items 2 and 3. Please take note in my previous comment about CourseState clashes.

https://www.powershellgallery.com/packages/PSGSuite/2.14.1

@IronKane2
Copy link

I tried creating a new GSCourse and received an error about permission. Should there be a param for domain? I am our Google domain SA. I tested the account permissions by creating a new student.

PS C:\Users> New-GSCourse -Name "Steve Test Class" -OwnerId srcampbell@ourdomain.net -Section s01 -Room "Secret Lab" -CourseState ACTIVE

New-GSCourse : Exception calling "Execute" with "0" argument(s): "Google.Apis.Requests.RequestError
The caller does not have permission [403]
Errors [
Message[The caller does not have permission] Location[ - ] Reason[forbidden] Domain[global]
]
"
At line:1 char:2

  • New-GSCourse -Name "Steve Test Class" -OwnerId srcampbell@ourdomain.net ...
  •  + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
     + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,New-GSCourse
    

@scrthq
Copy link
Member Author

scrthq commented Oct 3, 2018 via email

@IronKane2
Copy link

Yes I did. I double checked before posting. Then created a user to make sure I had a good session going.

@scrthq
Copy link
Member Author

scrthq commented Oct 3, 2018

Gotcha! Diving in! Thanks for continuing to pass these bumps along!

@scrthq
Copy link
Member Author

scrthq commented Oct 4, 2018

@IronKane2 - Just checked the scope for Get-GSCourse and it's correct. Are you managing multiple domains within your account and if so, is your AdminEmail within the same domain as the Classroom domain? Could you also try specifying a teacher's email for the -User parameter and see if that yields any different results?

@scrthq
Copy link
Member Author

scrthq commented Oct 4, 2018

also, confirmed that the scope for New-GSCourse appears to be correct as well.

Let me know if any of the Get-* Classroom functions work for you or if they're all returning 403's

Other things to confirm:

@IronKane2
Copy link

Students are in a child domain, but it wasn't referenced in the New-GSCourse cmd I executed. I've been using the Get-GSCourse with no issues. I looked at the API Client Access again and it looks good.

I was reading your 2nd link and my Admin Console has "Users can authorize apps to access their Google Classroom data." checked. Should that be unchecked?

@scrthq
Copy link
Member Author

scrthq commented Oct 4, 2018 via email

scrthq added a commit that referenced this issue Oct 5, 2018
scrthq added a commit that referenced this issue Oct 5, 2018
## 2.15.1
 * [Issue #87](#87)
  * Added `User` parameter to all Classroom functions to specify which user to authenticate the request as
* [Issue #90](#90)
  * Added `Update-GSUserPhoto`
  * Added `Remove-GSUserPhoto`
@scrthq
Copy link
Member Author

scrthq commented Oct 5, 2018

@IronKane2 - v2.15.1 deploying now with the additional -User parameter for all of the relevant classroom functions. Try it out with New-GSCourse by passing an admin user's email there for the Classroom domain. If there aren't any admins specific to that domain, I believe a teacher's email would suffice. Let me know if this gets you going!

@IronKane2
Copy link

I finally got it to work. Not sure what I did. I was trading emails with one of the helpful staff at AmplifiedIT and added my account to the classroom_teachers group. That might be what fixed it. It wasn't immediate and I just happened to try one more time. Thanks again for your hard work on this.

@scrthq
Copy link
Member Author

scrthq commented Oct 8, 2018

That's awesome to hear, @IronKane2! Any other issues that you've run into so far for the Classroom functions?

@IronKane2
Copy link

IronKane2 commented Oct 9, 2018

Add-GSCourseParticipant : Cannot convert argument "body", with value: "student@uni.edu", for "Create" to type "Google.Apis.Classroom.v1.Data.Student": "Cannot convert the "student@uni.edu" value of type 
"System.String" to type "Google.Apis.Classroom.v1.Data.Student"."
At line:1 char:1
+ Add-GSCourseParticipant -CourseId 19487328166 -Student student@uni. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Add-GSCourseParticipant

@IronKane2
Copy link

Looking at https://developers.google.com/classroom/guides/manage-users
It seems that it might want a student object and not a email string.

@scrthq
Copy link
Member Author

scrthq commented Oct 9, 2018

@IronKane2 - You are correct, I was just about to respond as well. I'm on it! Keeping sending any over as you run across them 👍

@scrthq
Copy link
Member Author

scrthq commented Oct 9, 2018

Found the issue! It's creating the Student object, but it's passing the email as the body parameter to the Create() method instead of the Student object. Fix coming up shortly!

@IronKane2
Copy link

I don't know if this is a bug, but Get-GSClassroomParticipants returns a Profile object with a email field that comes up blank.

@scrthq
Copy link
Member Author

scrthq commented Oct 9, 2018

Get-GSClassroomParticipants doesn't exist in the latest version (I believe that was only during the initial development). Check the version of PSGSuite you're running and update to 2.15.2 if you can; the function you're looking for is Get-GSCourseParticipant, I believe. Let me know if you have the same results there, checking into specifying Fields as well.

If you're still having issues on the latest version, can you send one of the resulting objects over so I can see what's being returned? The email/ID of the participant should be in the top-level UserId property of the returned object. If the object has Google.Apis.Classroom.v1.Data.UserProfile for the Profile property's value, you'll need to expand the Profile property to see the underlying values since it's another object.

@IronKane2
Copy link

IronKane2 commented Oct 9, 2018

sorry, I mis-typed.

PS C:\> Get-GSCourseParticipant -CourseId $t.Id

CourseId    Profile                                   UserId                ETag
--------    -------                                   ------                ----
19478966574 Google.Apis.Classroom.v1.Data.UserProfile 11403168604162104091     
19478966574 Google.Apis.Classroom.v1.Data.UserProfile 11824804976777876216     
19478966574 Google.Apis.Classroom.v1.Data.UserProfile 11053514128638965465     
19478966574 Google.Apis.Classroom.v1.Data.UserProfile 10845153571965700717     



PS C:\Users\djusdadmin> (Get-GSCourseParticipant -CourseId $t.Id).profile


EmailAddress    : 
Id              : 1140316860416210409
Name            : Google.Apis.Classroom.v1.Data.Name
Permissions     : {Google.Apis.Classroom.v1.Data.GlobalPermission}
PhotoUrl        : 
VerifiedTeacher : True
ETag            : 

EmailAddress    : 
Id              : 1182480497677787621
Name            : Google.Apis.Classroom.v1.Data.Name
Permissions     : 
PhotoUrl        : 
VerifiedTeacher : 
ETag            : 

EmailAddress    : 
Id              : 1105351412863896546
Name            : Google.Apis.Classroom.v1.Data.Name
Permissions     : 
PhotoUrl        : 
VerifiedTeacher : 
ETag            : 

EmailAddress    : 
Id              : 1084515357196570071
Name            : Google.Apis.Classroom.v1.Data.Name
Permissions     : 
PhotoUrl        : 
VerifiedTeacher : 
ETag            : 

@IronKane2
Copy link

I just spoke with my Director of Technology and she concurs about letting teachers remove students as a manual process on their end. Takes the target off of my back ;)

@scrthq
Copy link
Member Author

scrthq commented Nov 5, 2018

Makes sense! Worst case scenario, you can use Remove-GSCourseParticipant to automate things later =]

scrthq added a commit that referenced this issue Nov 6, 2018
…, add Sync-GSUserCache for #87

## 2.18.0

* [Issue #87](#87)
  * Added: `Get-GSCourseParticipant` and `Get-GSClassroomUserProfile` now have the `Fields` parameter
  * Added: `Sync-GSUserCache` to create a hashtable of users for quick lookups throughout scripts
* [Issue #53](#53) via [PR #108](#108) - _Thanks, [@dwrusse](https://github.com/dwrusse)!_
  * Added: `Get-GSContactList`
  * Added: `Remove-GSContact`
* Other additions via [PR #108](#108) - _Thanks, [@dwrusse](https://github.com/dwrusse)!_
  * Added: `Remove-GSCalendarEvent`
  * Added: `New-GSGmailLabel`
  * Added: `Remove-GSGmailLabel`
scrthq pushed a commit that referenced this issue Nov 6, 2018
…, add Sync-GSUserCache for #87

## 2.18.0

* [Issue #87](#87)
  * Added: `Get-GSCourseParticipant` and `Get-GSClassroomUserProfile` now have the `Fields` parameter
  * Added: `Sync-GSUserCache` to create a hashtable of users for quick lookups throughout scripts
* [Issue #53](#53) via [PR #108](#108) - _Thanks, [@dwrusse](https://github.com/dwrusse)!_
  * Added: `Get-GSContactList`
  * Added: `Remove-GSContact`
* Other additions via [PR #108](#108) - _Thanks, [@dwrusse](https://github.com/dwrusse)!_
  * Added: `Remove-GSCalendarEvent`
  * Added: `New-GSGmailLabel`
  * Added: `Remove-GSGmailLabel`
@scrthq
Copy link
Member Author

scrthq commented Nov 6, 2018

@IronKane2 - v2.18.0 with the Fields parameter on those 2 functions released! I also included Sync-GSUserCache, which fills the variable $global:GSUserCache with a hashtable containing the following keys by default (you can specify others with the Keys parameter):

  • PrimaryEmail
  • Id
  • All Aliases

Usage:

# Let it store in the global variable only
Sync-GSUserCache
$global:GSUserCache['user@domain.com'] # Gets the user object by primary email
$global:GSUserCache['u@domain.com'].PrimaryEmail # Gets a user's primary email via an alias

# Alternatively, include -PassThru and store it in a local variable as well
$hash = Sync-GSUserCache -PassThru
$hash['user@domain.com'] # Gets the user object by primary email
$hash['u@domain.com'].PrimaryEmail # Gets a user's primary email via an alias

# Supply a filter if you'd like to only sync a subset of users
$hash = Sync-GSUserCache -Filter "IsSuspended -eq '$false'"
$hash.Keys -contains 'activeuser@domain.com' # This would return True
$hash.Keys -contains 'suspendeduser@domain.com' # This would return false, even though it is a valid email in the domain

@scrthq
Copy link
Member Author

scrthq commented Nov 6, 2018

For usage on the Fields parameter, Fields for Google APIs usually follow one of the following naming conventions:

  • camelCase - -Fields primaryEmail,orgUnitPath
  • PascalCase - -Fields PrimaryEmail,OrgUnitPath

They also vary when specifying sub-property fields:

  • Dot-separated - -Fields 'profile.id','profile.emailAddress'
  • Slash-separated - -Fields 'profile/id','profile/emailAddress'

I would try out something like the following and see what returns, what throws an error, etc:

$t = (Get-GSCourse)[0]

# 1 - camelCase w/ top level fields only
Get-GSCourseParticipant -CourseId $t.Id -Fields id,profile,eTag

# 2 - camelCase w/ wildcard deeper field and slash separator
Get-GSCourseParticipant -CourseId $t.Id -Fields id,profile,'profile/*',eTag

# 3 - camelCase w/ specified deeper field and slash separator
Get-GSCourseParticipant -CourseId $t.Id -Fields id,profile,'profile/emailAddress',eTag

# 4 - camelCase w/ specified deeper field and dot separator
Get-GSCourseParticipant -CourseId $t.Id -Fields id,profile,'profile.emailAddress',eTag

# 5 - camelCase w/ wildcard deeper field and dot separator
Get-GSCourseParticipant -CourseId $t.Id -Fields id,profile,'profile.emailAddress',eTag

# 6 - PascalCase w/ top level fields only
Get-GSCourseParticipant -CourseId $t.Id -Fields Id,Profile,ETag

# 7 - PascalCase w/ wildcard deeper field and slash separator
Get-GSCourseParticipant -CourseId $t.Id -Fields Id,Profile,'Profile/*',ETag

# 8 - PascalCase w/ specified deeper field and slash separator
Get-GSCourseParticipant -CourseId $t.Id -Fields Id,Profile,'Profile/EmailAddress',ETag

# 8 - PascalCase w/ specified deeper field and dot separator
Get-GSCourseParticipant -CourseId $t.Id -Fields Id,Profile,'Profile.EmailAddress',ETag

# 8 - PascalCase w/ wildcard deeper field and dot separator
Get-GSCourseParticipant -CourseId $t.Id -Fields Id,Profile,'Profile.*',ETag

@jdstanberry
Copy link

I have a solution for Get-CourseParticipant not returning an email address. In $ServiceParams set the scope as @('https://www.googleapis.com/auth/classroom.rosters', 'https://www.googleapis.com/auth/classroom.profile.emails')

@scrthq
Copy link
Member Author

scrthq commented Nov 8, 2018

@jdstanberry - thank you! Going to get this updated and another version pushed out ASAP.

@jdstanberry
Copy link

jdstanberry commented Nov 8, 2018 via email

@scrthq
Copy link
Member Author

scrthq commented Nov 8, 2018

Made the update and confirmed it doesn't balk when trying to create the service. Thanks, @jdstanberry!! Should have this out shortly =]

image

scrthq pushed a commit that referenced this issue Nov 8, 2018
## 2.18.1

* [Issue #87](#87)
  * Added: Additional scopes during Service creation for `Get-GSCourseParticipant` and `Get-GSClassroomUserProfile` to enable pulling of full user profile information. - _Thanks, [@jdstanberry](https://github.com/jdstanberry)!_
* [Issue #111](#111)
  * Added: `DisableReminder` switch parameter to `New-GSCalendarEvent` and `Update-GSCalendarEvent` to remove Reminder inheritance from the calendar the event is on as well as any Reminder overload definitions.
* [Issue #53](#53)
  * Updated: `Get-GSContactList` and `Remove-GSContact` Token retrieval and overall cleanup
* Various/Other
  * Updated: `Get-GSToken` to align parameters more with `New-GoogleService`
scrthq added a commit that referenced this issue Nov 8, 2018
## 2.18.1

* [Issue #87](#87)
  * Added: Additional scopes during Service creation for `Get-GSCourseParticipant` and `Get-GSClassroomUserProfile` to enable pulling of full user profile information. - _Thanks, [@jdstanberry](https://github.com/jdstanberry)!_
* [Issue #111](#111)
  * Added: `DisableReminder` switch parameter to `New-GSCalendarEvent` and `Update-GSCalendarEvent` to remove Reminder inheritance from the calendar the event is on as well as any Reminder overload definitions.
* [Issue #53](#53)
  * Updated: `Get-GSContactList` and `Remove-GSContact` Token retrieval and overall cleanup
* Various/Other
  * Updated: `Get-GSToken` to align parameters more with `New-GoogleService`
@scrthq
Copy link
Member Author

scrthq commented Nov 8, 2018

Big thanks to @jdstanberry for pointing out the additional scopes!

@IronKane2 - v2.18.1 is now available on the PowerShell Gallery! Try it out and see if you're getting that EmailAddress value back now =]

@Foggy2
Copy link
Contributor

Foggy2 commented Nov 13, 2018

Posting in this issue as I suspect that it is linked to the changes that have been made. Using v2.18.1 Get-GSCourseParticipant appears to now be broken.

image

I have tested the same commands with v2.17.2 and the command works as intended.

@scrthq
Copy link
Member Author

scrthq commented Nov 13, 2018

@Foggy2 this is indeed the correct spot, thanks for testing and letting me know! Looks like overscoped on that one.

Can you try out Get-GSClassroomUserProfile and see if you're getting the same error?

Sent with GitHawk

@Foggy2
Copy link
Contributor

Foggy2 commented Nov 13, 2018

@scrthq Yes, same error.

image

@Foggy2
Copy link
Contributor

Foggy2 commented Nov 14, 2018

I see a reference to a similar error posted in this issue previously so posting again here to keep it all together.

I have reverted to v2.17.2 for the moment while the other error I posted above is being resolved. So the below is using v2.17.2.

image

I believe everything is configured correctly on my end:

  • I have verified that the scopes are present in the API Client access in Google Admin Console.
  • I can issue Get-* Classroom commands
  • I can use the Add-GSCourseParticipant command without error.
  • I even put the admin account in the classroom_teachers group.
  • I have also tried user the -User parameter and impersonating other teachers assigned to the course and other super admin accounts

Any thoughts why I can add teachers but not remove them?

@scrthq
Copy link
Member Author

scrthq commented Nov 14, 2018

@Foggy2 - Can you update your scopes for your Service Account in the Admin Console @ API Client Access? The Classroom API functions are pretty new, so there's a chance that you may not included the newer Classroom scopes when you set it up.

Here's the link to the Initial Setup page with instructions on accessing that page in the Admin Console: https://github.com/scrthq/PSGSuite/wiki/Initial-Setup#adding-api-client-access-in-admin-console

And here's the list of scopes that you'll need to copy/paste:

https://apps-apis.google.com/a/feeds/emailsettings/2.0/,
https://mail.google.com/,
https://sites.google.com/feeds,
https://www.google.com/m8/feeds/contacts,
https://www.googleapis.com/auth/activity,
https://www.googleapis.com/auth/admin.datatransfer,
https://www.googleapis.com/auth/admin.directory,
https://www.googleapis.com/auth/admin.directory.customer,
https://www.googleapis.com/auth/admin.directory.device.mobile,
https://www.googleapis.com/auth/admin.directory.domain,
https://www.googleapis.com/auth/admin.directory.group,
https://www.googleapis.com/auth/admin.directory.orgunit,
https://www.googleapis.com/auth/admin.directory.rolemanagement,
https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly,
https://www.googleapis.com/auth/admin.directory.user,
https://www.googleapis.com/auth/admin.directory.user.readonly,
https://www.googleapis.com/auth/admin.directory.user.security,
https://www.googleapis.com/auth/admin.directory.resource.calendar,
https://www.googleapis.com/auth/admin.directory.userschema,
https://www.googleapis.com/auth/admin.reports.audit.readonly,
https://www.googleapis.com/auth/admin.reports.usage.readonly,
https://www.googleapis.com/auth/apps.groups.settings,
https://www.googleapis.com/auth/apps.licensing,
https://www.googleapis.com/auth/calendar,
https://www.googleapis.com/auth/chat.bot,
https://www.googleapis.com/auth/drive,
https://www.googleapis.com/auth/gmail.settings.basic,
https://www.googleapis.com/auth/gmail.settings.sharing,
https://www.googleapis.com/auth/plus.login,
https://www.googleapis.com/auth/plus.me,
https://www.googleapis.com/auth/tasks,
https://www.googleapis.com/auth/tasks.readonly,
https://www.googleapis.com/auth/urlshortener,
https://www.googleapis.com/auth/userinfo.email,
https://www.googleapis.com/auth/userinfo.profile,
https://www.googleapis.com/auth/classroom.courses,
https://www.googleapis.com/auth/classroom.rosters,
https://www.googleapis.com/auth/classroom.rosters.readonly,
https://www.googleapis.com/auth/classroom.profile.emails,
https://www.googleapis.com/auth/classroom.profile.photos,
https://www.googleapis.com/auth/classroom.coursework.me,
https://www.googleapis.com/auth/classroom.coursework.students,
https://www.googleapis.com/auth/classroom.announcements,
https://www.googleapis.com/auth/classroom.guardianlinks.students,
https://www.googleapis.com/auth/classroom.push-notifications

@scrthq
Copy link
Member Author

scrthq commented Nov 14, 2018

I saw the first part of your message but should mention that I just updated the wiki to include the additional profile scopes

Sent with GitHawk

@Foggy2
Copy link
Contributor

Foggy2 commented Nov 14, 2018

@scrthq - Just double checked the scopes. I had all but the profiles scopes which I have now added.

Still getting the error though.

@Foggy2
Copy link
Contributor

Foggy2 commented Nov 14, 2018

@scrthq - Figured it out. The error was something on my part although it wasn't immediate clear what I was doing was not allowed.

The user I was attempting to remove from the class was set as the class owner. As soon as I changed the owner of the class to the other teacher assigned to the class, the Remove-GSCourseParticipant succeeded.

It would have been more useful if Google would provide a better error message other than 'The caller does not have permission' as this implies a scoping issue as you suggested.

This is illustrated in the below screen capture.

image

Would it be possible to test for this error condition upon receiving an error response from the API to help point other users towards the real cause? The Google API documentation did not mention this requirement at all. (At least in the pages I read trying to solve this) So I think other users would find it helpful if the real cause was indicated.

@scrthq
Copy link
Member Author

scrthq commented Nov 14, 2018

@Foggy2 -Thanks for digging in on that one and figuring it out! We should be able to test for that specific message, but I'd need to see if there are any other errors which could throw the same message. At the very least, the docs/comment based help can be updated to advise that removal of a course owner will return that error.

Considering you checked your scopes and re-pasted them recently, can you try out Get-GSCourseParticipant and/or Get-GSClassroomUserProfile to see if you're still getting the same errors as prior?

@Foggy2
Copy link
Contributor

Foggy2 commented Nov 14, 2018

@scrthq - Just tested using v2.19.0. Get-GSCourseParticipant and Get-GSClassroomUserProfile both are working with the extra scopes.

I can also confirm that the EmailAddress is populated in the returned results for both commands.

@scrthq
Copy link
Member Author

scrthq commented Nov 14, 2018

@Foggy2 - Fantastic, thank you for checking! Paging @IronKane2 to check when able as well =]. Follow up thanks to @jdstanberry for the pointer also.

@scrthq
Copy link
Member Author

scrthq commented Nov 25, 2018

Hey guys - going to close this out, as I feel like the Classroom functions are pretty stable now with no other outstanding issues to note. Feel free to open a new issue if anything new pops up!

@scrthq scrthq closed this as completed Nov 25, 2018
@IronKane2
Copy link

Hey all, I'm back. I was experiencing that error, but after getting caught up, I updated my scopes and it works great! Thank you so much for getting those email addresses in the Get-GSCourseParticipant.
I think you can put this to bed.

Sorry my posting is re-opening this, but I really wanted to express my appreciation for all your hard work. I love PSGSuite! You've made my life much easier.

@scrthq
Copy link
Member Author

scrthq commented Nov 29, 2018

Cheers, @IronKane2! ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants