Search in sources :

Example 6 with ApiResult

use of org.mediawiki.api.ApiResult in project apps-android-commons by commons-app.

the class UploadService method uploadContribution.

private void uploadContribution(Contribution contribution) {
    MWApi api = app.getMWApi();
    ApiResult result;
    InputStream file = null;
    String notificationTag = contribution.getLocalUri().toString();
    try {
        //FIXME: Google Photos bug
        file = this.getContentResolver().openInputStream(contribution.getLocalUri());
    } catch (FileNotFoundException e) {
        Timber.d("File not found");
        Toast fileNotFound = Toast.makeText(this, R.string.upload_failed, Toast.LENGTH_LONG);
        fileNotFound.show();
    }
    Timber.d("Before execution!");
    curProgressNotification = new NotificationCompat.Builder(this).setAutoCancel(true).setSmallIcon(R.drawable.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)).setAutoCancel(true).setContentTitle(getString(R.string.upload_progress_notification_title_start, contribution.getDisplayTitle())).setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload)).setOngoing(true).setProgress(100, 0, true).setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, ContributionsActivity.class), 0)).setTicker(getString(R.string.upload_progress_notification_title_in_progress, contribution.getDisplayTitle()));
    this.startForeground(NOTIFICATION_UPLOAD_IN_PROGRESS, curProgressNotification.build());
    String filename = null;
    try {
        filename = Utils.fixExtension(contribution.getFilename(), MimeTypeMap.getSingleton().getExtensionFromMimeType((String) contribution.getTag("mimeType")));
        synchronized (unfinishedUploads) {
            Timber.d("making sure of uniqueness of name: %s", filename);
            filename = findUniqueFilename(filename);
            unfinishedUploads.add(filename);
        }
        if (!api.validateLogin()) {
            // Need to revalidate!
            if (app.revalidateAuthToken()) {
                Timber.d("Successfully revalidated token!");
            } else {
                Timber.d("Unable to revalidate :(");
                // TODO: Put up a new notification, ask them to re-login
                stopForeground(true);
                Toast failureToast = Toast.makeText(this, R.string.authentication_failed, Toast.LENGTH_LONG);
                failureToast.show();
                return;
            }
        }
        NotificationUpdateProgressListener notificationUpdater = new NotificationUpdateProgressListener(notificationTag, getString(R.string.upload_progress_notification_title_in_progress, contribution.getDisplayTitle()), getString(R.string.upload_progress_notification_title_finishing, contribution.getDisplayTitle()), contribution);
        result = api.upload(filename, file, contribution.getDataLength(), contribution.getPageContents(), contribution.getEditSummary(), notificationUpdater);
        Timber.d("Response is %s", Utils.getStringFromDOM(result.getDocument()));
        curProgressNotification = null;
        String resultStatus = result.getString("/api/upload/@result");
        if (!resultStatus.equals("Success")) {
            String errorCode = result.getString("/api/error/@code");
            showFailedNotification(contribution);
            EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT).param("username", app.getCurrentAccount().name).param("source", contribution.getSource()).param("multiple", contribution.getMultiple()).param("result", errorCode).param("filename", contribution.getFilename()).log();
        } else {
            Date dateUploaded = null;
            dateUploaded = Utils.parseMWDate(result.getString("/api/upload/imageinfo/@timestamp"));
            // Title vs Filename
            String canonicalFilename = "File:" + result.getString("/api/upload/@filename").replace("_", " ");
            String imageUrl = result.getString("/api/upload/imageinfo/@url");
            contribution.setFilename(canonicalFilename);
            contribution.setImageUrl(imageUrl);
            contribution.setState(Contribution.STATE_COMPLETED);
            contribution.setDateUploaded(dateUploaded);
            contribution.save();
            EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT).param("username", app.getCurrentAccount().name).param("source", //FIXME
            contribution.getSource()).param("filename", contribution.getFilename()).param("multiple", contribution.getMultiple()).param("result", "success").log();
        }
    } catch (IOException e) {
        Timber.d("I have a network fuckup");
        showFailedNotification(contribution);
        return;
    } finally {
        if (filename != null) {
            unfinishedUploads.remove(filename);
        }
        toUpload--;
        if (toUpload == 0) {
            // Sync modifications right after all uplaods are processed
            ContentResolver.requestSync((CommonsApplication.getInstance()).getCurrentAccount(), ModificationsContentProvider.AUTHORITY, new Bundle());
            stopForeground(true);
        }
    }
}
Also used : InputStream(java.io.InputStream) Bundle(android.os.Bundle) FileNotFoundException(java.io.FileNotFoundException) Intent(android.content.Intent) PendingIntent(android.app.PendingIntent) IOException(java.io.IOException) Date(java.util.Date) ApiResult(org.mediawiki.api.ApiResult) Toast(android.widget.Toast) NotificationCompat(android.support.v4.app.NotificationCompat)

Example 7 with ApiResult

use of org.mediawiki.api.ApiResult in project apps-android-commons by commons-app.

the class ContributionsSyncAdapter method onPerformSync.

@Override
public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
    // This code is fraught with possibilities of race conditions, but lalalalala I can't hear you!
    String user = account.name;
    MWApi api = CommonsApplication.getInstance().getMWApi();
    SharedPreferences prefs = this.getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE);
    String lastModified = prefs.getString("lastSyncTimestamp", "");
    Date curTime = new Date();
    ApiResult result;
    Boolean done = false;
    String queryContinue = null;
    while (!done) {
        try {
            MWApi.RequestBuilder builder = api.action("query").param("list", "logevents").param("letype", "upload").param("leprop", "title|timestamp|ids").param("leuser", user).param("lelimit", getLimit());
            if (!TextUtils.isEmpty(lastModified)) {
                builder.param("leend", lastModified);
            }
            if (!TextUtils.isEmpty(queryContinue)) {
                builder.param("lestart", queryContinue);
            }
            result = builder.get();
        } catch (IOException e) {
            // There isn't really much we can do, eh?
            // FIXME: Perhaps add EventLogging?
            // Not sure if this does anything. Shitty docs
            syncResult.stats.numIoExceptions += 1;
            Timber.d("Syncing failed due to %s", e);
            return;
        }
        Timber.d("Last modified at %s", lastModified);
        ArrayList<ApiResult> uploads = result.getNodes("/api/query/logevents/item");
        Timber.d("%d results!", uploads.size());
        ArrayList<ContentValues> imageValues = new ArrayList<>();
        for (ApiResult image : uploads) {
            String pageId = image.getString("@pageid");
            if (pageId.equals("0")) {
                // means that this upload was deleted.
                continue;
            }
            String filename = image.getString("@title");
            if (fileExists(contentProviderClient, filename)) {
                Timber.d("Skipping %s", filename);
                continue;
            }
            String thumbUrl = Utils.makeThumbBaseUrl(filename);
            Date dateUpdated = Utils.parseMWDate(image.getString("@timestamp"));
            Contribution contrib = new Contribution(null, thumbUrl, filename, "", -1, dateUpdated, dateUpdated, user, "", "");
            contrib.setState(Contribution.STATE_COMPLETED);
            imageValues.add(contrib.toContentValues());
            if (imageValues.size() % COMMIT_THRESHOLD == 0) {
                try {
                    contentProviderClient.bulkInsert(ContributionsContentProvider.BASE_URI, imageValues.toArray(new ContentValues[] {}));
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }
                imageValues.clear();
            }
        }
        if (imageValues.size() != 0) {
            try {
                contentProviderClient.bulkInsert(ContributionsContentProvider.BASE_URI, imageValues.toArray(new ContentValues[] {}));
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
        }
        queryContinue = result.getString("/api/query-continue/logevents/@lestart");
        if (TextUtils.isEmpty(queryContinue)) {
            done = true;
        }
    }
    prefs.edit().putString("lastSyncTimestamp", Utils.toMWDate(curTime)).apply();
    Timber.d("Oh hai, everyone! Look, a kitty!");
}
Also used : ContentValues(android.content.ContentValues) SharedPreferences(android.content.SharedPreferences) ArrayList(java.util.ArrayList) IOException(java.io.IOException) Date(java.util.Date) ApiResult(org.mediawiki.api.ApiResult) MWApi(fr.free.nrw.commons.MWApi) RemoteException(android.os.RemoteException)

Example 8 with ApiResult

use of org.mediawiki.api.ApiResult in project apps-android-commons by commons-app.

the class UploadService method fileExistsWithName.

private static boolean fileExistsWithName(MWApi api, String fileName) throws IOException {
    ApiResult result;
    result = api.action("query").param("prop", "imageinfo").param("titles", "File:" + fileName).get();
    return result.getNodes("/api/query/pages/page/imageinfo").size() > 0;
}
Also used : ApiResult(org.mediawiki.api.ApiResult)

Example 9 with ApiResult

use of org.mediawiki.api.ApiResult in project apps-android-commons by commons-app.

the class ModificationsSyncAdapter method onPerformSync.

@Override
public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
    // This code is fraught with possibilities of race conditions, but lalalalala I can't hear you!
    Cursor allModifications;
    try {
        allModifications = contentProviderClient.query(ModificationsContentProvider.BASE_URI, null, null, null, null);
    } catch (RemoteException e) {
        throw new RuntimeException(e);
    }
    // Exit early if nothing to do
    if (allModifications == null || allModifications.getCount() == 0) {
        Timber.d("No modifications to perform");
        return;
    }
    String authCookie;
    try {
        authCookie = AccountManager.get(getContext()).blockingGetAuthToken(account, "", false);
    } catch (OperationCanceledException | AuthenticatorException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        Timber.d("Could not authenticate :(");
        return;
    }
    if (Utils.isNullOrWhiteSpace(authCookie)) {
        Timber.d("Could not authenticate :(");
        return;
    }
    MWApi api = CommonsApplication.getInstance().getMWApi();
    api.setAuthCookie(authCookie);
    String editToken;
    ApiResult requestResult, responseResult;
    try {
        editToken = api.getEditToken();
    } catch (IOException e) {
        Timber.d("Can not retreive edit token!");
        return;
    }
    allModifications.moveToFirst();
    Timber.d("Found %d modifications to execute", allModifications.getCount());
    ContentProviderClient contributionsClient = null;
    try {
        contributionsClient = getContext().getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
        while (!allModifications.isAfterLast()) {
            ModifierSequence sequence = ModifierSequence.fromCursor(allModifications);
            sequence.setContentProviderClient(contentProviderClient);
            Contribution contrib;
            Cursor contributionCursor;
            try {
                contributionCursor = contributionsClient.query(sequence.getMediaUri(), null, null, null, null);
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
            contributionCursor.moveToFirst();
            contrib = Contribution.fromCursor(contributionCursor);
            if (contrib.getState() == Contribution.STATE_COMPLETED) {
                try {
                    requestResult = api.action("query").param("prop", "revisions").param("rvprop", "timestamp|content").param("titles", contrib.getFilename()).get();
                } catch (IOException e) {
                    Timber.d("Network fuckup on modifications sync!");
                    continue;
                }
                Timber.d("Page content is %s", Utils.getStringFromDOM(requestResult.getDocument()));
                String pageContent = requestResult.getString("/api/query/pages/page/revisions/rev");
                String processedPageContent = sequence.executeModifications(contrib.getFilename(), pageContent);
                try {
                    responseResult = api.action("edit").param("title", contrib.getFilename()).param("token", editToken).param("text", processedPageContent).param("summary", sequence.getEditSummary()).post();
                } catch (IOException e) {
                    Timber.d("Network fuckup on modifications sync!");
                    continue;
                }
                Timber.d("Response is %s", Utils.getStringFromDOM(responseResult.getDocument()));
                String result = responseResult.getString("/api/edit/@result");
                if (!result.equals("Success")) {
                    // FIXME: Log this somewhere else
                    Timber.d("Non success result! %s", result);
                } else {
                    sequence.delete();
                }
            }
            allModifications.moveToNext();
        }
    } finally {
        if (contributionsClient != null) {
            contributionsClient.release();
        }
    }
}
Also used : OperationCanceledException(android.accounts.OperationCanceledException) AuthenticatorException(android.accounts.AuthenticatorException) IOException(java.io.IOException) Cursor(android.database.Cursor) ApiResult(org.mediawiki.api.ApiResult) MWApi(fr.free.nrw.commons.MWApi) RemoteException(android.os.RemoteException) ContentProviderClient(android.content.ContentProviderClient) Contribution(fr.free.nrw.commons.contributions.Contribution)

Example 10 with ApiResult

use of org.mediawiki.api.ApiResult in project apps-android-commons by commons-app.

the class ExistingFileAsync method doInBackground.

@Override
protected Boolean doInBackground(Void... voids) {
    MWApi api = CommonsApplication.getInstance().getMWApi();
    ApiResult result;
    // https://commons.wikimedia.org/w/api.php?action=query&list=allimages&format=xml&aisha1=801957214aba50cb63bb6eb1b0effa50188900ba
    try {
        result = api.action("query").param("format", "xml").param("list", "allimages").param("aisha1", fileSHA1).get();
        Timber.d("Searching Commons API for existing file: %s", result);
    } catch (IOException e) {
        Timber.e(e, "IO Exception: ");
        return false;
    }
    ArrayList<ApiResult> resultNodes = result.getNodes("/api/query/allimages/img");
    Timber.d("Result nodes: %s", resultNodes);
    boolean fileExists = !resultNodes.isEmpty();
    Timber.d("File already exists in Commons: %s", fileExists);
    return fileExists;
}
Also used : ApiResult(org.mediawiki.api.ApiResult) MWApi(fr.free.nrw.commons.MWApi) IOException(java.io.IOException)

Aggregations

ApiResult (org.mediawiki.api.ApiResult)11 IOException (java.io.IOException)7 MWApi (fr.free.nrw.commons.MWApi)6 ArrayList (java.util.ArrayList)4 RemoteException (android.os.RemoteException)2 Date (java.util.Date)2 AuthenticatorException (android.accounts.AuthenticatorException)1 OperationCanceledException (android.accounts.OperationCanceledException)1 PendingIntent (android.app.PendingIntent)1 ContentProviderClient (android.content.ContentProviderClient)1 ContentValues (android.content.ContentValues)1 Intent (android.content.Intent)1 SharedPreferences (android.content.SharedPreferences)1 Cursor (android.database.Cursor)1 Bundle (android.os.Bundle)1 NotificationCompat (android.support.v4.app.NotificationCompat)1 Toast (android.widget.Toast)1 Contribution (fr.free.nrw.commons.contributions.Contribution)1 FileNotFoundException (java.io.FileNotFoundException)1 InputStream (java.io.InputStream)1