aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtReOpen.java
blob: fcc1e3855c7cc554de739537a454525ebc367061 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//
// Copyright (C) 2019 The Qt Company
//


package com.googlesource.gerrit.plugins.qtcodereview;

import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.api.changes.RestoreInput;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.change.ChangeJson;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.RetryHelper;
import com.google.gerrit.server.update.RetryingRestModifyView;
import com.google.gerrit.server.update.UpdateException;
import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;


@Singleton
class QtReOpen extends RetryingRestModifyView<ChangeResource, RestoreInput, ChangeInfo>
               implements UiAction<ChangeResource> {

    private static final FluentLogger logger = FluentLogger.forEnclosingClass();

    private final Provider<ReviewDb> dbProvider;
    private final ChangeJson.Factory json;
    private final PatchSetUtil psUtil;
    private final ProjectCache projectCache;
    private final QtChangeUpdateOp.Factory qtUpdateFactory;

    @Inject
    QtReOpen(Provider<ReviewDb> dbProvider,
             ChangeJson.Factory json,
             PatchSetUtil psUtil,
             RetryHelper retryHelper,
             ProjectCache projectCache,
             QtChangeUpdateOp.Factory qtUpdateFactory) {
      super(retryHelper);
      this.dbProvider = dbProvider;
      this.json = json;
      this.psUtil = psUtil;
      this.projectCache = projectCache;
      this.qtUpdateFactory = qtUpdateFactory;
    }


    @Override
    protected ChangeInfo applyImpl(BatchUpdate.Factory updateFactory,
                                   ChangeResource rsrc,
                                   RestoreInput input)
                                   throws RestApiException, UpdateException,
                                          OrmException, PermissionBackendException,
                                          IOException {
        Change change = rsrc.getChange();
        logger.atInfo().log("qtcodereview: reopen %s", change);

        // Not allowed to restore if the current patch set is locked.
        psUtil.checkPatchSetNotLocked(rsrc.getNotes());

        // Use same permission as Restore. Note that Abandon permission grants the
        // Restore if the user also has push permission on the change’s destination ref.
        rsrc.permissions().database(dbProvider).check(ChangePermission.RESTORE);
        projectCache.checkedGet(rsrc.getProject()).checkStatePermitsWrite();

        if (change.getStatus() != Change.Status.DEFERRED) {
            logger.atSevere().log("qtcodereview: reopen %s status wrong %s", change, change.getStatus());
            throw new ResourceConflictException("change is " + ChangeUtil.status(change));
        }

        QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, "Reopened", input.message, null, null);
        try (BatchUpdate u =  updateFactory.create(dbProvider.get(), change.getProject(), rsrc.getUser(), TimeUtil.nowTs())) {
            u.addOp(rsrc.getId(), op).execute();
        }

        change = op.getChange();
        logger.atInfo().log("qtcodereview: reopened  %s", change);
        return json.noOptions().format(change);
    }

    @Override
    public UiAction.Description getDescription(ChangeResource rsrc) {
        UiAction.Description description = new UiAction.Description()
                                                       .setLabel("Reopen")
                                                       .setTitle("Reopen the change")
                                                       .setVisible(false);

        Change change = rsrc.getChange();
        if (change.getStatus() != Change.Status.DEFERRED) {
            return description;
        }

        try {
            if (!projectCache.checkedGet(rsrc.getProject()).statePermitsWrite()) {
                return description;
            }
        } catch (IOException e) {
            logger.atSevere().withCause(e).log("Failed to check if project state permits write: %s", rsrc.getProject());
            return description;
        }

        try {
            if (psUtil.isPatchSetLocked(rsrc.getNotes())) {
                return description;
            }
        } catch (OrmException | IOException e) {
            logger.atSevere().withCause(e).log("Failed to check if the current patch set of change %s is locked", change.getId());
            return description;
        }

        boolean visible = rsrc.permissions().database(dbProvider).testOrFalse(ChangePermission.RESTORE);
        return description.setVisible(visible);
    }

}