prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Assigning group members: memberlist batch navigation is broken.
  ## groupmembers listing batch and `showAll` link is broken
  
  ### What I did:
  
  Assign members to a group:
  
  - click on "show all" in the user filter.
  - if you have lots of users the list is batched
  - click on the next batch page
  
  ### What I expect to happen:
  
  the next user batch list is shown
  
  ### What actually happened:
  
  the user list is empty
  
  ### What version of Plone/ Addons I am using:
  
  Plone 6.0.2
  
  
  ### Additional
  
  The "toggle all" checkboxes do not work. This can be solved with `pat-checklist` ...
  
  </issue>
  <code>
  [start of Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py]
  1 from Products.CMFCore.utils import getToolByName
  2 from Products.CMFPlone import PloneMessageFactory as _
  3 from Products.CMFPlone.controlpanel.browser.usergroups import (
  4     UsersGroupsControlPanelView,
  5 )
  6 from Products.CMFPlone.utils import normalizeString
  7 from zExceptions import Forbidden
  8 
  9 
  10 class GroupMembershipControlPanel(UsersGroupsControlPanelView):
  11 
  12     def update(self):
  13         self.groupname = getattr(self.request, 'groupname')
  14         self.gtool = getToolByName(self, 'portal_groups')
  15         self.mtool = getToolByName(self, 'portal_membership')
  16         self.group = self.gtool.getGroupById(self.groupname)
  17         if self.group is None:
  18             return
  19 
  20         self.grouptitle = self.group.getGroupTitleOrName() or self.groupname
  21 
  22         self.request.set('grouproles', self.group.getRoles()
  23                          if self.group else [])
  24         self.canAddUsers = True
  25         if 'Manager' in self.request.get('grouproles') and not self.is_zope_manager:
  26             self.canAddUsers = False
  27 
  28         self.groupquery = self.makeQuery(groupname=self.groupname)
  29         self.groupkeyquery = self.makeQuery(key=self.groupname)
  30 
  31         form = self.request.form
  32         submitted = form.get('form.submitted', False)
  33 
  34         self.searchResults = []
  35         self.searchString = ''
  36         self.newSearch = False
  37 
  38         if submitted:
  39             # add/delete before we search so we don't show stale results
  40             toAdd = form.get('add', [])
  41             if toAdd:
  42                 if not self.canAddUsers:
  43                     raise Forbidden
  44 
  45                 for u in toAdd:
  46                     self.gtool.addPrincipalToGroup(
  47                         u, self.groupname, self.request)
  48                 self.context.plone_utils.addPortalMessage(_('Changes made.'))
  49 
  50             toDelete = form.get('delete', [])
  51             if toDelete:
  52                 for u in toDelete:
  53                     self.gtool.removePrincipalFromGroup(
  54                         u, self.groupname, self.request)
  55                 self.context.plone_utils.addPortalMessage(_('Changes made.'))
  56 
  57             search = form.get('form.button.Search', None) is not None
  58             edit = form.get('form.button.Edit', None) is not None and toDelete
  59             add = form.get('form.button.Add', None) is not None and toAdd
  60             findAll = form.get('form.button.FindAll', None) is not None and \
  61                 not self.many_users
  62             # The search string should be cleared when one of the
  63             # non-search buttons has been clicked.
  64             if findAll or edit or add:
  65                 form['searchstring'] = ''
  66             self.searchString = form.get('searchstring', '')
  67             if findAll or bool(self.searchString):
  68                 self.searchResults = self.getPotentialMembers(
  69                     self.searchString)
  70 
  71             if search or findAll:
  72                 self.newSearch = True
  73 
  74         self.groupMembers = self.getMembers()
  75 
  76     def __call__(self):
  77         self.update()
  78         return self.index()
  79 
  80     def isGroup(self, itemName):
  81         return self.gtool.isGroup(itemName)
  82 
  83     def getMembers(self):
  84         searchResults = self.gtool.getGroupMembers(self.groupname)
  85 
  86         groupResults = []
  87         userResults = []
  88         for principal_id in searchResults:
  89             principal = self.gtool.getGroupById(principal_id)
  90             if principal is not None:
  91                 groupResults.append(principal)
  92                 continue
  93             principal = self.mtool.getMemberById(principal_id)
  94             if principal is not None:
  95                 userResults.append(principal)
  96 
  97         groupResults.sort(key=lambda x: normalizeString(x.getGroupTitleOrName()))
  98         userResults.sort(key=lambda x: normalizeString(x.getProperty('fullname') or ''))
  99 
  100         return groupResults + userResults
  101 
  102     def getPotentialMembers(self, searchString):
  103         ignoredUsersGroups = [
  104             x.id for x in self.getMembers() + [self.group, ] if x is not None]
  105         return self.membershipSearch(searchString, ignore=ignoredUsersGroups)
  106
  [end of Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py
  --- a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py
  +++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py
  @@ -57,14 +57,21 @@
               search = form.get('form.button.Search', None) is not None
               edit = form.get('form.button.Edit', None) is not None and toDelete
               add = form.get('form.button.Add', None) is not None and toAdd
  -            findAll = form.get('form.button.FindAll', None) is not None and \
  -                not self.many_users
  +            isBatched = form.get("b_start", None) is not None
  +            findAll = (
  +                form.get('form.button.FindAll', None) is not None
  +                and not self.many_users
  +            )
  +            unbatchedAll = (
  +                form.get("showAll", "") == "y"
  +                and not self.many_users
  +            )
               # The search string should be cleared when one of the
               # non-search buttons has been clicked.
  -            if findAll or edit or add:
  +            if findAll or unbatchedAll or edit or add:
                   form['searchstring'] = ''
               self.searchString = form.get('searchstring', '')
  -            if findAll or bool(self.searchString):
  +            if findAll or isBatched or unbatchedAll or bool(self.searchString):
                   self.searchResults = self.getPotentialMembers(
                       self.searchString)
  
verification_info: {"golden_diff": "diff --git a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py\n--- a/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py\n+++ b/Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py\n@@ -57,14 +57,21 @@\n             search = form.get('form.button.Search', None) is not None\n             edit = form.get('form.button.Edit', None) is not None and toDelete\n             add = form.get('form.button.Add', None) is not None and toAdd\n-            findAll = form.get('form.button.FindAll', None) is not None and \\\n-                not self.many_users\n+            isBatched = form.get(\"b_start\", None) is not None\n+            findAll = (\n+                form.get('form.button.FindAll', None) is not None\n+                and not self.many_users\n+            )\n+            unbatchedAll = (\n+                form.get(\"showAll\", \"\") == \"y\"\n+                and not self.many_users\n+            )\n             # The search string should be cleared when one of the\n             # non-search buttons has been clicked.\n-            if findAll or edit or add:\n+            if findAll or unbatchedAll or edit or add:\n                 form['searchstring'] = ''\n             self.searchString = form.get('searchstring', '')\n-            if findAll or bool(self.searchString):\n+            if findAll or isBatched or unbatchedAll or bool(self.searchString):\n                 self.searchResults = self.getPotentialMembers(\n                     self.searchString)\n", "issue": "Assigning group members: memberlist batch navigation is broken.\n## groupmembers listing batch and `showAll` link is broken\r\n\r\n### What I did:\r\n\r\nAssign members to a group:\r\n\r\n- click on \"show all\" in the user filter.\r\n- if you have lots of users the list is batched\r\n- click on the next batch page\r\n\r\n### What I expect to happen:\r\n\r\nthe next user batch list is shown\r\n\r\n### What actually happened:\r\n\r\nthe user list is empty\r\n\r\n### What version of Plone/ Addons I am using:\r\n\r\nPlone 6.0.2\r\n\r\n\r\n### Additional\r\n\r\nThe \"toggle all\" checkboxes do not work. This can be solved with `pat-checklist` ...\n", "before_files": [{"content": "from Products.CMFCore.utils import getToolByName\nfrom Products.CMFPlone import PloneMessageFactory as _\nfrom Products.CMFPlone.controlpanel.browser.usergroups import (\n    UsersGroupsControlPanelView,\n)\nfrom Products.CMFPlone.utils import normalizeString\nfrom zExceptions import Forbidden\n\n\nclass GroupMembershipControlPanel(UsersGroupsControlPanelView):\n\n    def update(self):\n        self.groupname = getattr(self.request, 'groupname')\n        self.gtool = getToolByName(self, 'portal_groups')\n        self.mtool = getToolByName(self, 'portal_membership')\n        self.group = self.gtool.getGroupById(self.groupname)\n        if self.group is None:\n            return\n\n        self.grouptitle = self.group.getGroupTitleOrName() or self.groupname\n\n        self.request.set('grouproles', self.group.getRoles()\n                         if self.group else [])\n        self.canAddUsers = True\n        if 'Manager' in self.request.get('grouproles') and not self.is_zope_manager:\n            self.canAddUsers = False\n\n        self.groupquery = self.makeQuery(groupname=self.groupname)\n        self.groupkeyquery = self.makeQuery(key=self.groupname)\n\n        form = self.request.form\n        submitted = form.get('form.submitted', False)\n\n        self.searchResults = []\n        self.searchString = ''\n        self.newSearch = False\n\n        if submitted:\n            # add/delete before we search so we don't show stale results\n            toAdd = form.get('add', [])\n            if toAdd:\n                if not self.canAddUsers:\n                    raise Forbidden\n\n                for u in toAdd:\n                    self.gtool.addPrincipalToGroup(\n                        u, self.groupname, self.request)\n                self.context.plone_utils.addPortalMessage(_('Changes made.'))\n\n            toDelete = form.get('delete', [])\n            if toDelete:\n                for u in toDelete:\n                    self.gtool.removePrincipalFromGroup(\n                        u, self.groupname, self.request)\n                self.context.plone_utils.addPortalMessage(_('Changes made.'))\n\n            search = form.get('form.button.Search', None) is not None\n            edit = form.get('form.button.Edit', None) is not None and toDelete\n            add = form.get('form.button.Add', None) is not None and toAdd\n            findAll = form.get('form.button.FindAll', None) is not None and \\\n                not self.many_users\n            # The search string should be cleared when one of the\n            # non-search buttons has been clicked.\n            if findAll or edit or add:\n                form['searchstring'] = ''\n            self.searchString = form.get('searchstring', '')\n            if findAll or bool(self.searchString):\n                self.searchResults = self.getPotentialMembers(\n                    self.searchString)\n\n            if search or findAll:\n                self.newSearch = True\n\n        self.groupMembers = self.getMembers()\n\n    def __call__(self):\n        self.update()\n        return self.index()\n\n    def isGroup(self, itemName):\n        return self.gtool.isGroup(itemName)\n\n    def getMembers(self):\n        searchResults = self.gtool.getGroupMembers(self.groupname)\n\n        groupResults = []\n        userResults = []\n        for principal_id in searchResults:\n            principal = self.gtool.getGroupById(principal_id)\n            if principal is not None:\n                groupResults.append(principal)\n                continue\n            principal = self.mtool.getMemberById(principal_id)\n            if principal is not None:\n                userResults.append(principal)\n\n        groupResults.sort(key=lambda x: normalizeString(x.getGroupTitleOrName()))\n        userResults.sort(key=lambda x: normalizeString(x.getProperty('fullname') or ''))\n\n        return groupResults + userResults\n\n    def getPotentialMembers(self, searchString):\n        ignoredUsersGroups = [\n            x.id for x in self.getMembers() + [self.group, ] if x is not None]\n        return self.membershipSearch(searchString, ignore=ignoredUsersGroups)\n", "path": "Products/CMFPlone/controlpanel/browser/usergroups_groupmembership.py"}]}