Skip to content

Commit

Permalink
Delete and leave group
Browse files Browse the repository at this point in the history
  • Loading branch information
SmitaNachan committed Mar 13, 2023
1 parent 1c03031 commit 1c338dd
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 13 deletions.
1 change: 1 addition & 0 deletions Models/M365Group.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class M365Group
public string? DisplayName { get; set; }
public string? Description { get; set; }
public string? Visibility { get; set; }
public string? UserRole { get; set; }

public List<string>? Owners { get; set; }
public List<string>? Members { get; set; }
Expand Down
77 changes: 75 additions & 2 deletions Pages/GroupDetails.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
ViewData["Title"] = "M365 Group Details";
}

<script>
function showConfirmation(action) {
if (confirm("Are you sure you want to " + action + " this group?")) {
// Perform the delete action
document.getElementById("deleteGroupForm").submit();
}
}
</script>

<style>
body {
padding: 20px 0;
Expand All @@ -29,8 +38,12 @@
</tr>
</table>

<hr />

<p></p>
<div>Owners:</div>
<div>
<h4 class="display-8">Owners:</h4>
</div>
<table class="table table-striped border">
@foreach (var owner in Model.M365GroupDetails.Owners)
{
Expand All @@ -42,8 +55,32 @@
}
</table>

@if (Model.M365GroupDetails.UserRole == "Owner")
{
<form method="post" name="addOwners">
<input type="hidden" name="groupId" value="@Model.M365GroupDetails.Id" />
<div>
<div><b>Add Owners</b></div>
<table>
<tr>
<td>User Principal Name:</td>
<td>
<input type="text" asp-for="OwnerToAdd" placeholder="UPN of owner to add..." />
</td>
<td>
<input type="submit" id="btnAddOwner" value="Add Owner" asp-page-handler="AddOwner" />
</td>
</tr>
</table>
</div>
</form>
}
<hr />

<p></p>
<div>Members:</div>
<div>
<h4 class="display-8">Members:</h4>
</div>
<table class="table table-striped border">
@foreach (var member in Model.M365GroupDetails.Members)
{
Expand All @@ -54,5 +91,41 @@
</tr>
}
</table>

@if (Model.M365GroupDetails.UserRole == "Owner")
{
<form method="post" name="addMembers">
<input type="hidden" name="groupId" value="@Model.M365GroupDetails.Id" />
<div>
<div><b>Add Members</b></div>
<table>
<tr>
<td>User Principal Name:</td>
<td>
<input type="text" asp-for="MemberToAdd" placeholder="UPN of member to add..." />
</td>
<td>
<input type="submit" id="btnAddMember" value="Add Member" asp-page-handler="AddMember" />
</td>
</tr>
</table>
</div>
</form>
}

<hr />

<form method="post" name="deleteGroupForm">
<input type="hidden" name="groupId" value="@Model.M365GroupDetails.Id" />
<table>
<tr>
@if (Model.M365GroupDetails.UserRole == "Owner")
{
<td><input type="submit" id="btnDelete" value="Delete Group" onclick="showConfirmation('delete')" asp-page-handler="Delete" /></td>
}
<td><input type="submit" id="btnLeave" value="Leave Group" onclick="showConfirmation('leave')" asp-page-handler="Leave" /></td>
</tr>
</table>
</form>
</div>

98 changes: 90 additions & 8 deletions Pages/GroupDetails.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using hack_together_groups_manager.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
Expand All @@ -12,6 +13,15 @@ public class GroupDetailsModel : PageModel
private readonly GraphServiceClient _graphServiceClient;
public Models.M365Group M365GroupDetails { get; set; }

[BindProperty]
public string? GroupId { get; set; }

[BindProperty]
public string? MemberToAdd { get; set; }

[BindProperty]
public string? OwnerToAdd { get; set; }

public GroupDetailsModel(ILogger<IndexModel> logger, GraphServiceClient graphServiceClient)
{
_logger = logger;
Expand All @@ -20,22 +30,29 @@ public GroupDetailsModel(ILogger<IndexModel> logger, GraphServiceClient graphSer

public async Task OnGetAsync()
{
string groupId = HttpContext.Request.Query["groupId"];
var groupInfo = new Models.M365Group();
GroupId = HttpContext.Request.Query["groupId"];
M365Group groupInfo = await GetGroupInfo(GroupId);
M365GroupDetails = groupInfo;
}

if (groupId != null)
private async Task<M365Group> GetGroupInfo(string GroupId)
{
var groupInfo = new Models.M365Group();

if (GroupId != null)
{
var resultGroupInfo = await this._graphServiceClient.Groups[groupId].Request().GetAsync();
var resultGroupInfo = await this._graphServiceClient.Groups[GroupId].Request().GetAsync();
if (resultGroupInfo != null)
{
var group = resultGroupInfo as Microsoft.Graph.Group;

groupInfo.Id = group.Id;
groupInfo.Description = group.Description;
groupInfo.DisplayName = group.DisplayName;
groupInfo.Visibility = group.Visibility;
}

var resultMembersInfo = await this._graphServiceClient.Groups[groupId].Members.Request().GetAsync();
var resultMembersInfo = await this._graphServiceClient.Groups[GroupId].Members.Request().GetAsync();
if (resultMembersInfo != null)
{
groupInfo.Members = new List<string>();
Expand All @@ -45,18 +62,83 @@ public async Task OnGetAsync()
}
}

var resultOwnersInfo = await this._graphServiceClient.Groups[groupId].Owners.Request().GetAsync();
var me = await this._graphServiceClient.Me.Request().GetAsync();
var resultOwnersInfo = await this._graphServiceClient.Groups[GroupId].Owners.Request().GetAsync();
if (resultOwnersInfo != null)
{
groupInfo.Owners = new List<string>();
foreach (var owner in resultOwnersInfo)
{
groupInfo.Owners.Add((owner as Microsoft.Graph.User).UserPrincipalName);
var upn = (owner as Microsoft.Graph.User).UserPrincipalName;
if (me.UserPrincipalName == upn)
{
groupInfo.UserRole = "Owner";
}

groupInfo.Owners.Add(upn);
}
}
}

M365GroupDetails = groupInfo;
return groupInfo;
}

public async Task<IActionResult> OnPostDelete()
{
var groupIdValue = Request.Form["groupId"];
await this._graphServiceClient.Groups[groupIdValue.ToString()].Request().DeleteAsync();
return RedirectToPage("Index");
}

public async Task<IActionResult> OnPostLeave()
{
var groupIdValue = Request.Form["groupId"];
var me = await this._graphServiceClient.Me.Request().GetAsync();

M365Group groupInfo = await GetGroupInfo(groupIdValue);
if (groupInfo.UserRole == "Owner")
{
await this._graphServiceClient.Groups[groupIdValue.ToString()].Owners[me.Id].Reference.Request().DeleteAsync();
}

await this._graphServiceClient.Groups[groupIdValue.ToString()].Members[me.Id].Reference.Request().DeleteAsync();
return RedirectToPage("Index");
}

public async Task<IActionResult> OnPostAddOwner()
{
var ownerQuery = await this._graphServiceClient.Users.Request().Filter($"userPrincipalName eq '{OwnerToAdd}'").GetAsync();

var owner = ownerQuery.FirstOrDefault();
if (owner != null)
{
var groupIdValue = Request.Form["groupId"];
await this._graphServiceClient.Groups[groupIdValue].Owners.References.Request().AddAsync(owner);

M365Group groupInfo = await GetGroupInfo(groupIdValue);
M365GroupDetails = groupInfo;
OwnerToAdd = string.Empty;
}

return Page();
}

public async Task<IActionResult> OnPostAddMember()
{
var memberQuery = await this._graphServiceClient.Users.Request().Filter($"userPrincipalName eq '{MemberToAdd}'").GetAsync();

var member = memberQuery.FirstOrDefault();
if (member != null)
{
var groupIdValue = Request.Form["groupId"];
await this._graphServiceClient.Groups[groupIdValue].Members.References.Request().AddAsync(member);

M365Group groupInfo = await GetGroupInfo(groupIdValue);
M365GroupDetails = groupInfo;
MemberToAdd = string.Empty;
}

return Page();
}
}
}
2 changes: 1 addition & 1 deletion Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(new[] { "Directory.ReadWrite.All" , "User.Read"}).AddMicrosoftGraph().AddInMemoryTokenCaches();
.EnableTokenAcquisitionToCallDownstreamApi(new[] { "Group.ReadWrite.All", "User.Read" }).AddMicrosoftGraph().AddInMemoryTokenCaches();

builder.Services.AddAuthorization(options =>
{
Expand Down
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@

Created for [Microsoft Hack Together](https://github.com/microsoft/hack-together)


## Summary

Office 365 Groups is the foundational membership service, that drives all teamwork across Microsoft 365. Once in a group, we can get the benefits of the group-connected services like shared Outlook inbox, shared calendar, SharePoint site, Planner, Power BI, Yammer, and MS Teams.

This application gives a consolidated view of the Microsoft 365 groups owned by an user, as well they are member of it. This solution will help an individual to manage their group membership better.

This application will help organizations to achieve sustainability by ensuring the group well-being and reduce the carbon emissions by helping the owners to make quick decisions about the groups to manage and get rid off.

The application provides the below functionalities, to manage your groups better:

Role|Delete group|Leave group|Add owners|Add members|
----|------------|-----------|----------|-----------|
Group owner|Yes|Yes|Yes|Yes|
Group member|No|Yes|No|No


## Screenshots

Home page showing the M365 groups owned:
Expand All @@ -20,16 +31,43 @@ Member Groups page showing the M365 groups, an user is member of:

![Member Groups](./assets/member-groups.png)

Clicking the Group name will display additional information of the Group.
Clicking the Group name will display additional information of the Group and manage it better.

![Group Details](./assets/group-details.png)

Below operations can be performed to manage the groups better:

1. Delete group

If the group is not needed in the future, group owner can decide to delete it.

![Delete Group](./assets/delete-group.gif)

2. Leave group

User can leave the group membership, if they wish not to continue with the group.

![Leave Group](./assets/leave-group.gif)

3. Add owners

Existing owner can decide to add additional owners to the group. This will help while transfering the ownership of group during JML (Joiner, Mover, and Leaver) process.

![Add owners to Group](./assets/add-owner.gif)

4. Add members

Existing owner can decide to add additional members to the group.

![Add members to Group](./assets/add-member.gif)


## Minimal path to awesome

Follow below steps to use this app:
- Clone this repository
- Create an app registration in Azure AD with the following Microsoft Graph - delegated permissions:
- Directory.ReadWrite.All
- Group.ReadWrite.All
- User.Read

- Create a client secret for this app registration.
Expand All @@ -38,6 +76,7 @@ Follow below steps to use this app:
- `ClientId`: The client ID of the Azure AD application.
- `ClientSecret`: The client secret of the Azure AD application.


## Authors

* [Nanddeep Nachan](https://github.com/nanddeepn)
Expand Down
Binary file added assets/add-member.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/add-owner.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/delete-group.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/group-details.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/leave-group.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1c338dd

Please sign in to comment.