Skip to content

Commit 31ac506

Browse files
Merge pull request commons-app#1297 from diddypod/delete-request
Fix commons-app#1139: Nominate uploaded image for deletion
2 parents 80cc8b7 + 9a27f9c commit 31ac506

File tree

8 files changed

+295
-2
lines changed

8 files changed

+295
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package fr.free.nrw.commons.delete;
2+
3+
import android.app.AlertDialog;
4+
import android.content.Context;
5+
import android.content.DialogInterface;
6+
import android.content.Intent;
7+
import android.os.AsyncTask;
8+
import java.text.SimpleDateFormat;
9+
import java.util.Calendar;
10+
import java.util.Locale;
11+
12+
import javax.inject.Inject;
13+
14+
import fr.free.nrw.commons.Media;
15+
import fr.free.nrw.commons.R;
16+
import fr.free.nrw.commons.auth.SessionManager;
17+
import fr.free.nrw.commons.di.ApplicationlessInjection;
18+
import fr.free.nrw.commons.mwapi.MediaWikiApi;
19+
import timber.log.Timber;
20+
21+
import static android.support.v4.content.ContextCompat.startActivity;
22+
23+
public class DeleteTask extends AsyncTask<Void, Void, Integer> {
24+
25+
private static final int SUCCESS = 0;
26+
private static final int FAILED = -1;
27+
private static final int ALREADY_DELETED = -2;
28+
29+
@Inject MediaWikiApi mwApi;
30+
@Inject SessionManager sessionManager;
31+
32+
private Context context;
33+
private Media media;
34+
private String reason;
35+
36+
public DeleteTask (Context context, Media media, String reason){
37+
this.context = context;
38+
this.media = media;
39+
this.reason = reason;
40+
}
41+
42+
@Override
43+
protected void onPreExecute(){
44+
ApplicationlessInjection
45+
.getInstance(context.getApplicationContext())
46+
.getCommonsApplicationComponent()
47+
.inject(this);
48+
}
49+
50+
@Override
51+
protected Integer doInBackground(Void ...voids) {
52+
String editToken;
53+
String authCookie;
54+
String summary = "Nominating " + media.getFilename() +" for deletion.";
55+
56+
authCookie = sessionManager.getAuthCookie();
57+
mwApi.setAuthCookie(authCookie);
58+
59+
try{
60+
if (mwApi.pageExists("Commons:Deletion_requests/"+media.getFilename())){
61+
return ALREADY_DELETED;
62+
}
63+
}
64+
catch (Exception e) {
65+
Timber.d(e.getMessage());
66+
return FAILED;
67+
}
68+
69+
try {
70+
editToken = mwApi.getEditToken();
71+
}
72+
catch (Exception e){
73+
Timber.d(e.getMessage());
74+
return FAILED;
75+
}
76+
if (editToken.equals("+\\")) {
77+
return FAILED;
78+
}
79+
80+
Calendar calendar = Calendar.getInstance();
81+
String fileDeleteString = "{{delete|reason=" + reason +
82+
"|subpage=" +media.getFilename() +
83+
"|day=" + calendar.get(Calendar.DAY_OF_MONTH) +
84+
"|month=" + calendar.getDisplayName(Calendar.MONTH,Calendar.LONG, Locale.getDefault()) +
85+
"|year=" + calendar.get(Calendar.YEAR) +
86+
"}}";
87+
try{
88+
mwApi.prependEdit(editToken,fileDeleteString+"\n",
89+
media.getFilename(),summary);
90+
}
91+
catch (Exception e) {
92+
Timber.d(e.getMessage());
93+
return FAILED;
94+
}
95+
96+
String subpageString = "=== [[:" + media.getFilename() + "]] ===\n" +
97+
reason +
98+
" ~~~~";
99+
try{
100+
mwApi.edit(editToken,subpageString+"\n",
101+
"Commons:Deletion_requests/"+media.getFilename(),summary);
102+
}
103+
catch (Exception e) {
104+
Timber.d(e.getMessage());
105+
return FAILED;
106+
}
107+
108+
String logPageString = "\n{{Commons:Deletion requests/" + media.getFilename() +
109+
"}}\n";
110+
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
111+
String date = sdf.format(calendar.getTime());
112+
try{
113+
mwApi.appendEdit(editToken,logPageString+"\n",
114+
"Commons:Deletion_requests/"+date,summary);
115+
}
116+
catch (Exception e) {
117+
Timber.d(e.getMessage());
118+
return FAILED;
119+
}
120+
121+
String userPageString = "\n{{subst:idw|" + media.getFilename() +
122+
"}} ~~~~";
123+
try{
124+
mwApi.appendEdit(editToken,userPageString+"\n",
125+
"User_Talk:"+sessionManager.getCurrentAccount().name,summary);
126+
}
127+
catch (Exception e) {
128+
Timber.d(e.getMessage());
129+
return FAILED;
130+
}
131+
return SUCCESS;
132+
}
133+
134+
@Override
135+
protected void onPostExecute(Integer result) {
136+
String message = "";
137+
String title = "";
138+
switch (result){
139+
case SUCCESS:
140+
title = "Success";
141+
message = "Successfully nominated " + media.getDisplayTitle() + " deletion.\n" +
142+
"Check the webpage for more details";
143+
break;
144+
case FAILED:
145+
title = "Failed";
146+
message = "Could not request deletion. Something went wrong.";
147+
break;
148+
case ALREADY_DELETED:
149+
title = "Already Nominated";
150+
message = media.getDisplayTitle() + " has already been nominated for deletion.\n" +
151+
"Check the webpage for more details";
152+
break;
153+
}
154+
AlertDialog alert;
155+
AlertDialog.Builder builder = new AlertDialog.Builder(context);
156+
builder.setTitle(title);
157+
builder.setMessage(message);
158+
builder.setCancelable(true);
159+
builder.setPositiveButton(
160+
R.string.ok,
161+
new DialogInterface.OnClickListener() {
162+
public void onClick(DialogInterface dialog, int id) {}
163+
});
164+
builder.setNeutralButton(R.string.view_browser,
165+
new DialogInterface.OnClickListener() {
166+
public void onClick(DialogInterface dialog, int id) {
167+
Intent browserIntent = new Intent(Intent.ACTION_VIEW, media.getFilePageTitle().getMobileUri());
168+
startActivity(context,browserIntent,null);
169+
}
170+
});
171+
alert = builder.create();
172+
alert.show();
173+
}
174+
}

app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java

+5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
import fr.free.nrw.commons.CommonsApplication;
1010
import fr.free.nrw.commons.MediaWikiImageView;
1111
import fr.free.nrw.commons.auth.LoginActivity;
12+
import fr.free.nrw.commons.contributions.Contribution;
13+
import fr.free.nrw.commons.contributions.ContributionsActivity;
1214
import fr.free.nrw.commons.contributions.ContributionsSyncAdapter;
15+
import fr.free.nrw.commons.delete.DeleteTask;
1316
import fr.free.nrw.commons.modifications.ModificationsSyncAdapter;
1417
import fr.free.nrw.commons.settings.SettingsFragment;
1518

@@ -34,6 +37,8 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
3437

3538
void inject(LoginActivity activity);
3639

40+
void inject(DeleteTask deleteTask);
41+
3742
void inject(SettingsFragment fragment);
3843

3944
@Override

app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java

+58
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
package fr.free.nrw.commons.media;
22

3+
import android.app.AlertDialog;
4+
import android.content.DialogInterface;
35
import android.content.Intent;
46
import android.database.DataSetObserver;
57
import android.net.Uri;
68
import android.os.AsyncTask;
79
import android.os.Bundle;
810
import android.support.annotation.Nullable;
11+
import android.text.Editable;
12+
import android.text.TextWatcher;
913
import android.util.TypedValue;
1014
import android.view.LayoutInflater;
1115
import android.view.View;
1216
import android.view.ViewGroup;
1317
import android.view.ViewTreeObserver;
18+
import android.view.WindowManager;
19+
import android.widget.Button;
20+
import android.widget.EditText;
1421
import android.widget.LinearLayout;
1522
import android.widget.ScrollView;
1623
import android.widget.TextView;
@@ -32,6 +39,7 @@
3239
import fr.free.nrw.commons.MediaWikiImageView;
3340
import fr.free.nrw.commons.PageTitle;
3441
import fr.free.nrw.commons.R;
42+
import fr.free.nrw.commons.delete.DeleteTask;
3543
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
3644
import fr.free.nrw.commons.location.LatLng;
3745
import fr.free.nrw.commons.ui.widget.CompatTextView;
@@ -72,6 +80,7 @@ public static MediaDetailFragment forMedia(int index, boolean editable) {
7280
private TextView coordinates;
7381
private TextView uploadedDate;
7482
private LinearLayout categoryContainer;
83+
private Button delete;
7584
private ScrollView scrollView;
7685
private ArrayList<String> categoryNames;
7786
private boolean categoriesLoaded = false;
@@ -124,6 +133,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
124133
license = (TextView) view.findViewById(R.id.mediaDetailLicense);
125134
coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates);
126135
uploadedDate = (TextView) view.findViewById(R.id.mediaDetailuploadeddate);
136+
delete = (Button) view.findViewById(R.id.nominateDeletion);
127137
categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer);
128138

129139
licenseList = new LicenseList(getActivity());
@@ -273,6 +283,8 @@ private void setTextFields(Media media) {
273283
categoryNames.add(getString(R.string.detail_panel_cats_none));
274284
}
275285
rebuildCatList();
286+
287+
delete.setVisibility(View.VISIBLE);
276288
}
277289

278290
private void setOnClickListeners(final Media media) {
@@ -285,6 +297,52 @@ private void setOnClickListeners(final Media media) {
285297
if (media.getCoordinates() != null) {
286298
coordinates.setOnClickListener(v -> openMap(media.getCoordinates()));
287299
}
300+
if (delete.getVisibility()==View.VISIBLE){
301+
delete.setOnClickListener(v -> {
302+
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
303+
alert.setMessage("Why should this file be deleted?");
304+
final EditText input = new EditText(getActivity());
305+
alert.setView(input);
306+
input.requestFocus();
307+
alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
308+
public void onClick(DialogInterface dialog, int whichButton) {
309+
String reason = input.getText().toString();
310+
DeleteTask deleteTask = new DeleteTask(getActivity(), media, reason);
311+
deleteTask.execute();
312+
}
313+
});
314+
alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
315+
public void onClick(DialogInterface dialog, int whichButton) {
316+
}
317+
});
318+
AlertDialog d = alert.create();
319+
input.addTextChangedListener(new TextWatcher() {
320+
private void handleText() {
321+
final Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE);
322+
if (input.getText().length() == 0) {
323+
okButton.setEnabled(false);
324+
} else {
325+
okButton.setEnabled(true);
326+
}
327+
}
328+
329+
@Override
330+
public void afterTextChanged(Editable arg0) {
331+
handleText();
332+
}
333+
334+
@Override
335+
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
336+
}
337+
338+
@Override
339+
public void onTextChanged(CharSequence s, int start, int before, int count) {
340+
}
341+
});
342+
d.show();
343+
d.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
344+
});
345+
}
288346
}
289347

290348
private void rebuildCatList() {

app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java

+33
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,14 @@ public boolean fileExistsWithName(String fileName) throws IOException {
205205
.getNodes("/api/query/pages/page/imageinfo").size() > 0;
206206
}
207207

208+
@Override
209+
public boolean pageExists(String pageName) throws IOException {
210+
return Double.parseDouble( api.action("query")
211+
.param("titles", pageName)
212+
.get()
213+
.getString("/api/query/pages/page/@_idx")) != -1;
214+
}
215+
208216
@Override
209217
@Nullable
210218
public String edit(String editToken, String processedPageContent, String filename, String summary) throws IOException {
@@ -217,6 +225,31 @@ public String edit(String editToken, String processedPageContent, String filenam
217225
.getString("/api/edit/@result");
218226
}
219227

228+
229+
@Override
230+
@Nullable
231+
public String appendEdit(String editToken, String processedPageContent, String filename, String summary) throws IOException {
232+
return api.action("edit")
233+
.param("title", filename)
234+
.param("token", editToken)
235+
.param("appendtext", processedPageContent)
236+
.param("summary", summary)
237+
.post()
238+
.getString("/api/edit/@result");
239+
}
240+
241+
@Override
242+
@Nullable
243+
public String prependEdit(String editToken, String processedPageContent, String filename, String summary) throws IOException {
244+
return api.action("edit")
245+
.param("title", filename)
246+
.param("token", editToken)
247+
.param("prependtext", processedPageContent)
248+
.param("summary", summary)
249+
.post()
250+
.getString("/api/edit/@result");
251+
}
252+
220253
@Override
221254
public String findThumbnailByFilename(String filename) throws IOException {
222255
return api.action("query")

app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public interface MediaWikiApi {
2828

2929
boolean fileExistsWithName(String fileName) throws IOException;
3030

31+
boolean pageExists(String pageName) throws IOException;
32+
3133
String findThumbnailByFilename(String filename) throws IOException;
3234

3335
boolean logEvents(LogBuilder[] logBuilders);
@@ -38,6 +40,12 @@ public interface MediaWikiApi {
3840
@Nullable
3941
String edit(String editToken, String processedPageContent, String filename, String summary) throws IOException;
4042

43+
@Nullable
44+
String prependEdit(String editToken, String processedPageContent, String filename, String summary) throws IOException;
45+
46+
@Nullable
47+
String appendEdit(String editToken, String processedPageContent, String filename, String summary) throws IOException;
48+
4149
@NonNull
4250
MediaResult fetchMediaByFilename(String filename) throws IOException;
4351

@@ -58,8 +66,6 @@ public interface MediaWikiApi {
5866

5967
boolean existingFile(String fileSha1) throws IOException;
6068

61-
62-
6369
@NonNull
6470
LogEventResult logEvents(String user, String lastModified, String queryContinue, int limit) throws IOException;
6571

0 commit comments

Comments
 (0)