memberships: handlers endpoint rework (#129)

* reworked api endpoints

* minor fix
diff --git a/core/auth/memberships/group.html b/core/auth/memberships/group.html
index a9cbb66..3995fb7 100644
--- a/core/auth/memberships/group.html
+++ b/core/auth/memberships/group.html
@@ -14,9 +14,8 @@
         <p class="description">{{ .Description }}</p>
     </div>
     <hr class="divider">
-    <form action="/add-user" method="post">
-        <input type="hidden" id="group-name" name="group" value="{{ .GroupName }}">
-        <label for="group-name">Username:</label>
+    <form action="/group/{{ .GroupName }}/add-user/" method="post">
+        <label>Username:</label>
         <input type="text" id="username" name="username" required>
         <label for="status">Status:</label>
         <select id="status" name="status" required>
@@ -26,8 +25,7 @@
         <button type="submit">Add Member</button>
     </form>
     <hr class="divider">
-    <form action="/add-child-group" method="post">
-        <input type="hidden" id="parent-group" name="parent-group" value="{{ .GroupName }}">
+    <form action="/group/{{ .GroupName }}/add-child-group" method="post">
         <label for="child-group">Select Child Group:</label>
         <select id="child-group" name="child-group" required>
             {{- range .AvailableGroups }}
@@ -46,7 +44,7 @@
         <tr>
             <td><a href="/user/{{ . }}">{{ . }}</a></td>
             <td>
-                <form action="/remove-group-owner/{{ $parentGroupName }}/{{ . }}" method="post" onsubmit="return confirm('Are you sure you want to revoke user {{ . }} ownership of the {{ $parentGroupName }} group?')">
+                <form action="/group/{{ $parentGroupName }}/remove-owner/{{ . }}" method="post" onsubmit="return confirm('Are you sure you want to revoke user {{ . }} ownership of the {{ $parentGroupName }} group?')">
                     <button type="submit" class="button">Remove</button>
                 </form>
             </td>
@@ -63,7 +61,7 @@
         <tr>
             <td><a href="/user/{{ . }}">{{ . }}</a></td>
             <td>
-                <form action="/remove-group-member/{{ $parentGroupName }}/{{ . }}" method="post" onsubmit="return confirm('Are you sure you want to remove user {{ . }} user from {{ $parentGroupName }} group?')">
+                <form action="/group/{{ $parentGroupName }}/remove-member/{{ . }}" method="post" onsubmit="return confirm('Are you sure you want to remove user {{ . }} user from {{ $parentGroupName }} group?')">
                     <button type="submit" class="button">Remove</button>
                 </form>
             </td>
@@ -95,7 +93,7 @@
             <td><a href="/group/{{ .Name }}">{{ .Name }}</a></td>
             <td>{{ .Description }}</td>
             <td>
-                <form action="/remove-child-group/{{ $parentGroupName }}/{{ .Name }}" method="post" onsubmit="return confirm('Are you sure you want to remove group {{ .Name }} as a child of the group {{ $parentGroupName }}?')">
+                <form action="/group/{{ $parentGroupName }}/remove-child-group/{{ .Name }}" method="post" onsubmit="return confirm('Are you sure you want to remove group {{ .Name }} as a child of the group {{ $parentGroupName }}?')">
                     <button type="submit" class="button">Remove</button>
                 </form>
             </td>
diff --git a/core/auth/memberships/main.go b/core/auth/memberships/main.go
index 8df9356..f8f2cff 100644
--- a/core/auth/memberships/main.go
+++ b/core/auth/memberships/main.go
@@ -526,13 +526,14 @@
 	go func() {
 		r := mux.NewRouter()
 		r.PathPrefix("/static/").Handler(http.FileServer(http.FS(staticResources)))
-		r.HandleFunc("/remove-child-group/{parent-group}/{child-group}", s.removeChildGroupHandler)
-		r.HandleFunc("/remove-{action}/{group-name}/{username}", s.removeUserFromGroupHandler)
+		r.HandleFunc("/group/{group-name}/add-user/", s.addUserToGroupHandler)
+		r.HandleFunc("/group/{parent-group}/add-child-group", s.addChildGroupHandler)
+		r.HandleFunc("/group/{parent-group}/remove-child-group/{child-group}", s.removeChildGroupHandler)
+		r.HandleFunc("/group/{group-name}/remove-owner/{username}", s.removeOwnerFromGroupHandler)
+		r.HandleFunc("/group/{group-name}/remove-member/{username}", s.removeMemberFromGroupHandler)
 		r.HandleFunc("/group/{group-name}", s.groupHandler)
 		r.HandleFunc("/user/{username}", s.userHandler)
 		r.HandleFunc("/create-group", s.createGroupHandler)
-		r.HandleFunc("/add-user", s.addUserHandler)
-		r.HandleFunc("/add-child-group", s.addChildGroupHandler)
 		r.HandleFunc("/", s.homePageHandler)
 		e <- http.ListenAndServe(fmt.Sprintf(":%d", *port), r)
 	}()
@@ -756,7 +757,7 @@
 	}
 }
 
-func (s *Server) removeUserFromGroupHandler(w http.ResponseWriter, r *http.Request) {
+func (s *Server) removeOwnerFromGroupHandler(w http.ResponseWriter, r *http.Request) {
 	loggedInUser, err := getLoggedInUser(r)
 	if err != nil {
 		http.Error(w, "User Not Logged In", http.StatusUnauthorized)
@@ -766,17 +767,7 @@
 		vars := mux.Vars(r)
 		username := vars["username"]
 		groupName := vars["group-name"]
-		action := vars["action"]
-		var tableName string
-		switch action {
-		case "group-owner":
-			tableName = "owners"
-		case "group-member":
-			tableName = "user_to_group"
-		default:
-			http.Error(w, "action not found", http.StatusBadRequest)
-			return
-		}
+		tableName := "owners"
 		if err := isValidGroupName(groupName); err != nil {
 			http.Error(w, err.Error(), http.StatusBadRequest)
 			return
@@ -794,7 +785,35 @@
 	}
 }
 
-func (s *Server) addUserHandler(w http.ResponseWriter, r *http.Request) {
+func (s *Server) removeMemberFromGroupHandler(w http.ResponseWriter, r *http.Request) {
+	loggedInUser, err := getLoggedInUser(r)
+	if err != nil {
+		http.Error(w, "User Not Logged In", http.StatusUnauthorized)
+		return
+	}
+	if r.Method == http.MethodPost {
+		vars := mux.Vars(r)
+		username := vars["username"]
+		groupName := vars["group-name"]
+		tableName := "user_to_group"
+		if err := isValidGroupName(groupName); err != nil {
+			http.Error(w, err.Error(), http.StatusBadRequest)
+			return
+		}
+		if _, err := s.checkIsOwner(w, loggedInUser, groupName); err != nil {
+			http.Error(w, err.Error(), http.StatusUnauthorized)
+			return
+		}
+		err := s.store.RemoveUserFromTable(username, groupName, tableName)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+		http.Redirect(w, r, "/group/"+groupName, http.StatusSeeOther)
+	}
+}
+
+func (s *Server) addUserToGroupHandler(w http.ResponseWriter, r *http.Request) {
 	if r.Method != http.MethodPost {
 		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
 		return
@@ -804,7 +823,8 @@
 		http.Error(w, "User Not Logged In", http.StatusUnauthorized)
 		return
 	}
-	groupName := r.FormValue("group")
+	vars := mux.Vars(r)
+	groupName := vars["group-name"]
 	if err := isValidGroupName(groupName); err != nil {
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
@@ -850,7 +870,8 @@
 		http.Error(w, "User Not Logged In", http.StatusUnauthorized)
 		return
 	}
-	parentGroup := r.FormValue("parent-group")
+	vars := mux.Vars(r)
+	parentGroup := vars["parent-group"]
 	if err := isValidGroupName(parentGroup); err != nil {
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return