We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Vote for suggestion when adding duplicate
Currently duplicate suggestions are ignored, but it would be better if it would be accepted as upvote in case voting is enabled for given translation.

See also https://github.com/WeblateOrg/weblate/issues/1348#issuecomment-280706768

<bountysource-plugin>

---
Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/42236397-vote-for-suggestion-when-adding-duplicate?utm_campaign=plugin&utm_content=tracker%2F253393&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F253393&utm_medium=issues&utm_source=github).
</bountysource-plugin>

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `weblate/trans/models/suggestion.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright © 2012 - 2018 Michal Čihař <michal@cihar.com>
4 #
5 # This file is part of Weblate <https://weblate.org/>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 #
20 
21 from __future__ import unicode_literals
22 
23 from django.conf import settings
24 from django.db import models, transaction
25 from django.db.models import Count
26 from django.utils.encoding import python_2_unicode_compatible
27 from django.utils.translation import ugettext as _
28 
29 from weblate.lang.models import Language
30 from weblate.trans.models.change import Change
31 from weblate.utils.unitdata import UnitData
32 from weblate.trans.mixins import UserDisplayMixin
33 from weblate.utils import messages
34 from weblate.utils.antispam import report_spam
35 from weblate.utils.fields import JSONField
36 from weblate.utils.state import STATE_TRANSLATED
37 from weblate.utils.request import get_ip_address
38 
39 
40 class SuggestionManager(models.Manager):
41     # pylint: disable=no-init
42 
43     def add(self, unit, target, request, vote=False):
44         """Create new suggestion for this unit."""
45         user = request.user
46 
47         same = self.filter(
48             target=target,
49             content_hash=unit.content_hash,
50             language=unit.translation.language,
51             project=unit.translation.component.project,
52         )
53 
54         if same.exists() or (unit.target == target and not unit.fuzzy):
55             return False
56 
57         # Create the suggestion
58         suggestion = self.create(
59             target=target,
60             content_hash=unit.content_hash,
61             language=unit.translation.language,
62             project=unit.translation.component.project,
63             user=user,
64             userdetails={
65                 'address': get_ip_address(request),
66                 'agent': request.META.get('HTTP_USER_AGENT', ''),
67             },
68         )
69 
70         # Record in change
71         for aunit in suggestion.related_units:
72             Change.objects.create(
73                 unit=aunit,
74                 action=Change.ACTION_SUGGESTION,
75                 user=user,
76                 target=target,
77                 author=user
78             )
79 
80         # Add unit vote
81         if vote:
82             suggestion.add_vote(
83                 unit.translation,
84                 request,
85                 True
86             )
87 
88         # Notify subscribed users
89         from weblate.accounts.notifications import notify_new_suggestion
90         notify_new_suggestion(unit, suggestion, user)
91 
92         # Update suggestion stats
93         if user is not None:
94             user.profile.suggested += 1
95             user.profile.save()
96 
97         return True
98 
99     def copy(self, project):
100         """Copy suggestions to new project
101 
102         This is used on moving component to other project and ensures nothing
103         is lost. We don't actually look where the suggestion belongs as it
104         would make the operation really expensive and it should be done in the
105         cleanup cron job.
106         """
107         for suggestion in self.all():
108             Suggestion.objects.create(
109                 project=project,
110                 target=suggestion.target,
111                 content_hash=suggestion.content_hash,
112                 user=suggestion.user,
113                 language=suggestion.language,
114             )
115 
116 
117 @python_2_unicode_compatible
118 class Suggestion(UnitData, UserDisplayMixin):
119     target = models.TextField()
120     user = models.ForeignKey(
121         settings.AUTH_USER_MODEL, null=True, blank=True,
122         on_delete=models.deletion.CASCADE
123     )
124     userdetails = JSONField()
125     language = models.ForeignKey(
126         Language, on_delete=models.deletion.CASCADE
127     )
128     timestamp = models.DateTimeField(auto_now_add=True)
129 
130     votes = models.ManyToManyField(
131         settings.AUTH_USER_MODEL,
132         through='Vote',
133         related_name='user_votes'
134     )
135 
136     objects = SuggestionManager()
137 
138     class Meta(object):
139         app_label = 'trans'
140         ordering = ['-timestamp']
141         index_together = [
142             ('project', 'language', 'content_hash'),
143         ]
144 
145     def __str__(self):
146         return 'suggestion for {0} by {1}'.format(
147             self.content_hash,
148             self.user.username if self.user else 'unknown',
149         )
150 
151     @transaction.atomic
152     def accept(self, translation, request, permission='suggestion.accept'):
153         allunits = translation.unit_set.select_for_update().filter(
154             content_hash=self.content_hash,
155         )
156         failure = False
157         for unit in allunits:
158             if not request.user.has_perm(permission, unit):
159                 failure = True
160                 messages.error(request, _('Failed to accept suggestion!'))
161                 continue
162 
163             # Skip if there is no change
164             if unit.target == self.target and unit.state >= STATE_TRANSLATED:
165                 continue
166 
167             unit.target = self.target
168             unit.state = STATE_TRANSLATED
169             unit.save_backend(
170                 request, change_action=Change.ACTION_ACCEPT, user=self.user
171             )
172 
173         if not failure:
174             self.delete()
175 
176     def delete_log(self, user, change=Change.ACTION_SUGGESTION_DELETE,
177                    is_spam=False):
178         """Delete with logging change"""
179         if is_spam and self.userdetails:
180             report_spam(
181                 self.userdetails['address'],
182                 self.userdetails['agent'],
183                 self.target
184             )
185         for unit in self.related_units:
186             Change.objects.create(
187                 unit=unit,
188                 action=change,
189                 user=user,
190                 target=self.target,
191                 author=user
192             )
193         self.delete()
194 
195     def get_num_votes(self):
196         """Return number of votes."""
197         votes = Vote.objects.filter(suggestion=self)
198         positive = votes.filter(positive=True).aggregate(Count('id'))
199         negative = votes.filter(positive=False).aggregate(Count('id'))
200         return positive['id__count'] - negative['id__count']
201 
202     def add_vote(self, translation, request, positive):
203         """Add (or updates) vote for a suggestion."""
204         if not request.user.is_authenticated:
205             return
206 
207         vote, created = Vote.objects.get_or_create(
208             suggestion=self,
209             user=request.user,
210             defaults={'positive': positive}
211         )
212         if not created or vote.positive != positive:
213             vote.positive = positive
214             vote.save()
215 
216         # Automatic accepting
217         required_votes = translation.component.suggestion_autoaccept
218         if required_votes and self.get_num_votes() >= required_votes:
219             self.accept(translation, request, 'suggestion.vote')
220 
221 
222 @python_2_unicode_compatible
223 class Vote(models.Model):
224     """Suggestion voting."""
225     suggestion = models.ForeignKey(
226         Suggestion, on_delete=models.deletion.CASCADE
227     )
228     user = models.ForeignKey(
229         settings.AUTH_USER_MODEL, on_delete=models.deletion.CASCADE
230     )
231     positive = models.BooleanField(default=True)
232 
233     class Meta(object):
234         unique_together = ('suggestion', 'user')
235         app_label = 'trans'
236 
237     def __str__(self):
238         if self.positive:
239             vote = '+1'
240         else:
241             vote = '-1'
242         return '{0} for {1} by {2}'.format(
243             vote,
244             self.suggestion,
245             self.user.username,
246         )
247
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/weblate/trans/models/suggestion.py b/weblate/trans/models/suggestion.py
--- a/weblate/trans/models/suggestion.py
+++ b/weblate/trans/models/suggestion.py
@@ -35,6 +35,7 @@
 from weblate.utils.fields import JSONField
 from weblate.utils.state import STATE_TRANSLATED
 from weblate.utils.request import get_ip_address
+from django.core.exceptions import ObjectDoesNotExist
 
 
 class SuggestionManager(models.Manager):
@@ -44,15 +45,22 @@
         """Create new suggestion for this unit."""
         user = request.user
 
-        same = self.filter(
-            target=target,
-            content_hash=unit.content_hash,
-            language=unit.translation.language,
-            project=unit.translation.component.project,
-        )
+        try:
+            same = self.get(
+                target=target,
+                content_hash=unit.content_hash,
+                language=unit.translation.language,
+                project=unit.translation.component.project,
+            )
+
+            if same.user == user or not vote:
+                return False
+            else:
+                same.add_vote(unit.translation, request, True)
+                return False
 
-        if same.exists() or (unit.target == target and not unit.fuzzy):
-            return False
+        except ObjectDoesNotExist:
+            pass
 
         # Create the suggestion
         suggestion = self.create(

{"golden_diff": "diff --git a/weblate/trans/models/suggestion.py b/weblate/trans/models/suggestion.py\n--- a/weblate/trans/models/suggestion.py\n+++ b/weblate/trans/models/suggestion.py\n@@ -35,6 +35,7 @@\n from weblate.utils.fields import JSONField\n from weblate.utils.state import STATE_TRANSLATED\n from weblate.utils.request import get_ip_address\n+from django.core.exceptions import ObjectDoesNotExist\n \n \n class SuggestionManager(models.Manager):\n@@ -44,15 +45,22 @@\n         \"\"\"Create new suggestion for this unit.\"\"\"\n         user = request.user\n \n-        same = self.filter(\n-            target=target,\n-            content_hash=unit.content_hash,\n-            language=unit.translation.language,\n-            project=unit.translation.component.project,\n-        )\n+        try:\n+            same = self.get(\n+                target=target,\n+                content_hash=unit.content_hash,\n+                language=unit.translation.language,\n+                project=unit.translation.component.project,\n+            )\n+\n+            if same.user == user or not vote:\n+                return False\n+            else:\n+                same.add_vote(unit.translation, request, True)\n+                return False\n \n-        if same.exists() or (unit.target == target and not unit.fuzzy):\n-            return False\n+        except ObjectDoesNotExist:\n+            pass\n \n         # Create the suggestion\n         suggestion = self.create(\n", "issue": "Vote for suggestion when adding duplicate\nCurrently duplicate suggestions are ignored, but it would be better if it would be accepted as upvote in case voting is enabled for given translation.\r\n\r\nSee also https://github.com/WeblateOrg/weblate/issues/1348#issuecomment-280706768\r\n\r\n<bountysource-plugin>\r\n\r\n---\r\nWant to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/42236397-vote-for-suggestion-when-adding-duplicate?utm_campaign=plugin&utm_content=tracker%2F253393&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F253393&utm_medium=issues&utm_source=github).\r\n</bountysource-plugin>\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright \u00a9 2012 - 2018 Michal \u010ciha\u0159 <michal@cihar.com>\n#\n# This file is part of Weblate <https://weblate.org/>\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n#\n\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import models, transaction\nfrom django.db.models import Count\nfrom django.utils.encoding import python_2_unicode_compatible\nfrom django.utils.translation import ugettext as _\n\nfrom weblate.lang.models import Language\nfrom weblate.trans.models.change import Change\nfrom weblate.utils.unitdata import UnitData\nfrom weblate.trans.mixins import UserDisplayMixin\nfrom weblate.utils import messages\nfrom weblate.utils.antispam import report_spam\nfrom weblate.utils.fields import JSONField\nfrom weblate.utils.state import STATE_TRANSLATED\nfrom weblate.utils.request import get_ip_address\n\n\nclass SuggestionManager(models.Manager):\n    # pylint: disable=no-init\n\n    def add(self, unit, target, request, vote=False):\n        \"\"\"Create new suggestion for this unit.\"\"\"\n        user = request.user\n\n        same = self.filter(\n            target=target,\n            content_hash=unit.content_hash,\n            language=unit.translation.language,\n            project=unit.translation.component.project,\n        )\n\n        if same.exists() or (unit.target == target and not unit.fuzzy):\n            return False\n\n        # Create the suggestion\n        suggestion = self.create(\n            target=target,\n            content_hash=unit.content_hash,\n            language=unit.translation.language,\n            project=unit.translation.component.project,\n            user=user,\n            userdetails={\n                'address': get_ip_address(request),\n                'agent': request.META.get('HTTP_USER_AGENT', ''),\n            },\n        )\n\n        # Record in change\n        for aunit in suggestion.related_units:\n            Change.objects.create(\n                unit=aunit,\n                action=Change.ACTION_SUGGESTION,\n                user=user,\n                target=target,\n                author=user\n            )\n\n        # Add unit vote\n        if vote:\n            suggestion.add_vote(\n                unit.translation,\n                request,\n                True\n            )\n\n        # Notify subscribed users\n        from weblate.accounts.notifications import notify_new_suggestion\n        notify_new_suggestion(unit, suggestion, user)\n\n        # Update suggestion stats\n        if user is not None:\n            user.profile.suggested += 1\n            user.profile.save()\n\n        return True\n\n    def copy(self, project):\n        \"\"\"Copy suggestions to new project\n\n        This is used on moving component to other project and ensures nothing\n        is lost. We don't actually look where the suggestion belongs as it\n        would make the operation really expensive and it should be done in the\n        cleanup cron job.\n        \"\"\"\n        for suggestion in self.all():\n            Suggestion.objects.create(\n                project=project,\n                target=suggestion.target,\n                content_hash=suggestion.content_hash,\n                user=suggestion.user,\n                language=suggestion.language,\n            )\n\n\n@python_2_unicode_compatible\nclass Suggestion(UnitData, UserDisplayMixin):\n    target = models.TextField()\n    user = models.ForeignKey(\n        settings.AUTH_USER_MODEL, null=True, blank=True,\n        on_delete=models.deletion.CASCADE\n    )\n    userdetails = JSONField()\n    language = models.ForeignKey(\n        Language, on_delete=models.deletion.CASCADE\n    )\n    timestamp = models.DateTimeField(auto_now_add=True)\n\n    votes = models.ManyToManyField(\n        settings.AUTH_USER_MODEL,\n        through='Vote',\n        related_name='user_votes'\n    )\n\n    objects = SuggestionManager()\n\n    class Meta(object):\n        app_label = 'trans'\n        ordering = ['-timestamp']\n        index_together = [\n            ('project', 'language', 'content_hash'),\n        ]\n\n    def __str__(self):\n        return 'suggestion for {0} by {1}'.format(\n            self.content_hash,\n            self.user.username if self.user else 'unknown',\n        )\n\n    @transaction.atomic\n    def accept(self, translation, request, permission='suggestion.accept'):\n        allunits = translation.unit_set.select_for_update().filter(\n            content_hash=self.content_hash,\n        )\n        failure = False\n        for unit in allunits:\n            if not request.user.has_perm(permission, unit):\n                failure = True\n                messages.error(request, _('Failed to accept suggestion!'))\n                continue\n\n            # Skip if there is no change\n            if unit.target == self.target and unit.state >= STATE_TRANSLATED:\n                continue\n\n            unit.target = self.target\n            unit.state = STATE_TRANSLATED\n            unit.save_backend(\n                request, change_action=Change.ACTION_ACCEPT, user=self.user\n            )\n\n        if not failure:\n            self.delete()\n\n    def delete_log(self, user, change=Change.ACTION_SUGGESTION_DELETE,\n                   is_spam=False):\n        \"\"\"Delete with logging change\"\"\"\n        if is_spam and self.userdetails:\n            report_spam(\n                self.userdetails['address'],\n                self.userdetails['agent'],\n                self.target\n            )\n        for unit in self.related_units:\n            Change.objects.create(\n                unit=unit,\n                action=change,\n                user=user,\n                target=self.target,\n                author=user\n            )\n        self.delete()\n\n    def get_num_votes(self):\n        \"\"\"Return number of votes.\"\"\"\n        votes = Vote.objects.filter(suggestion=self)\n        positive = votes.filter(positive=True).aggregate(Count('id'))\n        negative = votes.filter(positive=False).aggregate(Count('id'))\n        return positive['id__count'] - negative['id__count']\n\n    def add_vote(self, translation, request, positive):\n        \"\"\"Add (or updates) vote for a suggestion.\"\"\"\n        if not request.user.is_authenticated:\n            return\n\n        vote, created = Vote.objects.get_or_create(\n            suggestion=self,\n            user=request.user,\n            defaults={'positive': positive}\n        )\n        if not created or vote.positive != positive:\n            vote.positive = positive\n            vote.save()\n\n        # Automatic accepting\n        required_votes = translation.component.suggestion_autoaccept\n        if required_votes and self.get_num_votes() >= required_votes:\n            self.accept(translation, request, 'suggestion.vote')\n\n\n@python_2_unicode_compatible\nclass Vote(models.Model):\n    \"\"\"Suggestion voting.\"\"\"\n    suggestion = models.ForeignKey(\n        Suggestion, on_delete=models.deletion.CASCADE\n    )\n    user = models.ForeignKey(\n        settings.AUTH_USER_MODEL, on_delete=models.deletion.CASCADE\n    )\n    positive = models.BooleanField(default=True)\n\n    class Meta(object):\n        unique_together = ('suggestion', 'user')\n        app_label = 'trans'\n\n    def __str__(self):\n        if self.positive:\n            vote = '+1'\n        else:\n            vote = '-1'\n        return '{0} for {1} by {2}'.format(\n            vote,\n            self.suggestion,\n            self.user.username,\n        )\n", "path": "weblate/trans/models/suggestion.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright \u00a9 2012 - 2018 Michal \u010ciha\u0159 <michal@cihar.com>\n#\n# This file is part of Weblate <https://weblate.org/>\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <https://www.gnu.org/licenses/>.\n#\n\nfrom __future__ import unicode_literals\n\nfrom django.conf import settings\nfrom django.db import models, transaction\nfrom django.db.models import Count\nfrom django.utils.encoding import python_2_unicode_compatible\nfrom django.utils.translation import ugettext as _\n\nfrom weblate.lang.models import Language\nfrom weblate.trans.models.change import Change\nfrom weblate.utils.unitdata import UnitData\nfrom weblate.trans.mixins import UserDisplayMixin\nfrom weblate.utils import messages\nfrom weblate.utils.antispam import report_spam\nfrom weblate.utils.fields import JSONField\nfrom weblate.utils.state import STATE_TRANSLATED\nfrom weblate.utils.request import get_ip_address\nfrom django.core.exceptions import ObjectDoesNotExist\n\n\nclass SuggestionManager(models.Manager):\n    # pylint: disable=no-init\n\n    def add(self, unit, target, request, vote=False):\n        \"\"\"Create new suggestion for this unit.\"\"\"\n        user = request.user\n\n        try:\n            same = self.get(\n                target=target,\n                content_hash=unit.content_hash,\n                language=unit.translation.language,\n                project=unit.translation.component.project,\n            )\n\n            if same.user == user or not vote:\n                return False\n            else:\n                same.add_vote(unit.translation, request, True)\n                return False\n\n        except ObjectDoesNotExist:\n            pass\n\n        # Create the suggestion\n        suggestion = self.create(\n            target=target,\n            content_hash=unit.content_hash,\n            language=unit.translation.language,\n            project=unit.translation.component.project,\n            user=user,\n            userdetails={\n                'address': get_ip_address(request),\n                'agent': request.META.get('HTTP_USER_AGENT', ''),\n            },\n        )\n\n        # Record in change\n        for aunit in suggestion.related_units:\n            Change.objects.create(\n                unit=aunit,\n                action=Change.ACTION_SUGGESTION,\n                user=user,\n                target=target,\n                author=user\n            )\n\n        # Add unit vote\n        if vote:\n            suggestion.add_vote(\n                unit.translation,\n                request,\n                True\n            )\n\n        # Notify subscribed users\n        from weblate.accounts.notifications import notify_new_suggestion\n        notify_new_suggestion(unit, suggestion, user)\n\n        # Update suggestion stats\n        if user is not None:\n            user.profile.suggested += 1\n            user.profile.save()\n\n        return True\n\n    def copy(self, project):\n        \"\"\"Copy suggestions to new project\n\n        This is used on moving component to other project and ensures nothing\n        is lost. We don't actually look where the suggestion belongs as it\n        would make the operation really expensive and it should be done in the\n        cleanup cron job.\n        \"\"\"\n        for suggestion in self.all():\n            Suggestion.objects.create(\n                project=project,\n                target=suggestion.target,\n                content_hash=suggestion.content_hash,\n                user=suggestion.user,\n                language=suggestion.language,\n            )\n\n\n@python_2_unicode_compatible\nclass Suggestion(UnitData, UserDisplayMixin):\n    target = models.TextField()\n    user = models.ForeignKey(\n        settings.AUTH_USER_MODEL, null=True, blank=True,\n        on_delete=models.deletion.CASCADE\n    )\n    userdetails = JSONField()\n    language = models.ForeignKey(\n        Language, on_delete=models.deletion.CASCADE\n    )\n    timestamp = models.DateTimeField(auto_now_add=True)\n\n    votes = models.ManyToManyField(\n        settings.AUTH_USER_MODEL,\n        through='Vote',\n        related_name='user_votes'\n    )\n\n    objects = SuggestionManager()\n\n    class Meta(object):\n        app_label = 'trans'\n        ordering = ['-timestamp']\n        index_together = [\n            ('project', 'language', 'content_hash'),\n        ]\n\n    def __str__(self):\n        return 'suggestion for {0} by {1}'.format(\n            self.content_hash,\n            self.user.username if self.user else 'unknown',\n        )\n\n    @transaction.atomic\n    def accept(self, translation, request, permission='suggestion.accept'):\n        allunits = translation.unit_set.select_for_update().filter(\n            content_hash=self.content_hash,\n        )\n        failure = False\n        for unit in allunits:\n            if not request.user.has_perm(permission, unit):\n                failure = True\n                messages.error(request, _('Failed to accept suggestion!'))\n                continue\n\n            # Skip if there is no change\n            if unit.target == self.target and unit.state >= STATE_TRANSLATED:\n                continue\n\n            unit.target = self.target\n            unit.state = STATE_TRANSLATED\n            unit.save_backend(\n                request, change_action=Change.ACTION_ACCEPT, user=self.user\n            )\n\n        if not failure:\n            self.delete()\n\n    def delete_log(self, user, change=Change.ACTION_SUGGESTION_DELETE,\n                   is_spam=False):\n        \"\"\"Delete with logging change\"\"\"\n        if is_spam and self.userdetails:\n            report_spam(\n                self.userdetails['address'],\n                self.userdetails['agent'],\n                self.target\n            )\n        for unit in self.related_units:\n            Change.objects.create(\n                unit=unit,\n                action=change,\n                user=user,\n                target=self.target,\n                author=user\n            )\n        self.delete()\n\n    def get_num_votes(self):\n        \"\"\"Return number of votes.\"\"\"\n        votes = Vote.objects.filter(suggestion=self)\n        positive = votes.filter(positive=True).aggregate(Count('id'))\n        negative = votes.filter(positive=False).aggregate(Count('id'))\n        return positive['id__count'] - negative['id__count']\n\n    def add_vote(self, translation, request, positive):\n        \"\"\"Add (or updates) vote for a suggestion.\"\"\"\n        if not request.user.is_authenticated:\n            return\n\n        vote, created = Vote.objects.get_or_create(\n            suggestion=self,\n            user=request.user,\n            defaults={'positive': positive}\n        )\n        if not created or vote.positive != positive:\n            vote.positive = positive\n            vote.save()\n\n        # Automatic accepting\n        required_votes = translation.component.suggestion_autoaccept\n        if required_votes and self.get_num_votes() >= required_votes:\n            self.accept(translation, request, 'suggestion.vote')\n\n\n@python_2_unicode_compatible\nclass Vote(models.Model):\n    \"\"\"Suggestion voting.\"\"\"\n    suggestion = models.ForeignKey(\n        Suggestion, on_delete=models.deletion.CASCADE\n    )\n    user = models.ForeignKey(\n        settings.AUTH_USER_MODEL, on_delete=models.deletion.CASCADE\n    )\n    positive = models.BooleanField(default=True)\n\n    class Meta(object):\n        unique_together = ('suggestion', 'user')\n        app_label = 'trans'\n\n    def __str__(self):\n        if self.positive:\n            vote = '+1'\n        else:\n            vote = '-1'\n        return '{0} for {1} by {2}'.format(\n            vote,\n            self.suggestion,\n            self.user.username,\n        )\n", "path": "weblate/trans/models/suggestion.py"}]}