forked from Archives/Athou_commafeed
import from google reader
This commit is contained in:
11
pom.xml
11
pom.xml
@@ -173,6 +173,17 @@
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.oauth-client</groupId>
|
||||
<artifactId>google-oauth-client-servlet</artifactId>
|
||||
<version>1.14.1-beta</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client-jackson2</artifactId>
|
||||
<version>1.14.1-beta</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
|
||||
@@ -11,10 +11,12 @@ import javax.inject.Inject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.commafeed.backend.dao.ApplicationSettingsService;
|
||||
import com.commafeed.backend.dao.FeedCategoryService;
|
||||
import com.commafeed.backend.dao.FeedService;
|
||||
import com.commafeed.backend.dao.FeedSubscriptionService;
|
||||
import com.commafeed.backend.dao.UserService;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
@@ -44,6 +46,9 @@ public class StartupBean {
|
||||
@Inject
|
||||
PasswordEncryptionService encryptionService;
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
private long startupTime;
|
||||
|
||||
@PostConstruct
|
||||
@@ -52,6 +57,8 @@ public class StartupBean {
|
||||
if (userService.getCount() == 0) {
|
||||
log.info("Populating database with default values");
|
||||
|
||||
applicationSettingsService.save(new ApplicationSettings());
|
||||
|
||||
User user = userService.register(ADMIN_NAME, "admin",
|
||||
Arrays.asList(Role.ADMIN, Role.USER));
|
||||
userService.register("test", "test", Arrays.asList(Role.USER));
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.uaihebert.factory.EasyCriteriaFactory;
|
||||
import com.uaihebert.model.EasyCriteria;
|
||||
|
||||
@Stateless
|
||||
public class ApplicationSettingsService {
|
||||
|
||||
@PersistenceContext
|
||||
protected EntityManager em;
|
||||
|
||||
public void save(ApplicationSettings settings) {
|
||||
if (settings.getId() == null) {
|
||||
em.persist(settings);
|
||||
} else {
|
||||
em.merge(settings);
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationSettings get() {
|
||||
EasyCriteria<ApplicationSettings> criteria = EasyCriteriaFactory
|
||||
.createQueryCriteria(em, ApplicationSettings.class);
|
||||
List<ApplicationSettings> list = criteria.getResultList();
|
||||
return Iterables.getFirst(list, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.commafeed.backend.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "APPLICATIONSETTINGS")
|
||||
@SuppressWarnings("serial")
|
||||
public class ApplicationSettings extends AbstractModel {
|
||||
|
||||
private String publicUrl;
|
||||
private boolean allowRegistrations = false;
|
||||
private String googleClientId;
|
||||
private String googleClientSecret;
|
||||
|
||||
public String getPublicUrl() {
|
||||
return publicUrl;
|
||||
}
|
||||
|
||||
public void setPublicUrl(String publicUrl) {
|
||||
this.publicUrl = publicUrl;
|
||||
}
|
||||
|
||||
public boolean isAllowRegistrations() {
|
||||
return allowRegistrations;
|
||||
}
|
||||
|
||||
public void setAllowRegistrations(boolean allowRegistrations) {
|
||||
this.allowRegistrations = allowRegistrations;
|
||||
}
|
||||
|
||||
public String getGoogleClientId() {
|
||||
return googleClientId;
|
||||
}
|
||||
|
||||
public void setGoogleClientId(String googleClientId) {
|
||||
this.googleClientId = googleClientId;
|
||||
}
|
||||
|
||||
public String getGoogleClientSecret() {
|
||||
return googleClientSecret;
|
||||
}
|
||||
|
||||
public void setGoogleClientSecret(String googleClientSecret) {
|
||||
this.googleClientSecret = googleClientSecret;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,6 +21,10 @@ public class User extends AbstractModel {
|
||||
@Index(name = "username_index")
|
||||
private String name;
|
||||
|
||||
@Column(length = 256, unique = true)
|
||||
@Index(name = "useremail_index")
|
||||
private String email;
|
||||
|
||||
@Column(length = 256, nullable = false)
|
||||
private byte[] password;
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.commafeed.frontend.pages.FaviconPage;
|
||||
import com.commafeed.frontend.pages.GoogleImportCallbackPage;
|
||||
import com.commafeed.frontend.pages.GoogleImportRedirectPage;
|
||||
import com.commafeed.frontend.pages.HomePage;
|
||||
import com.commafeed.frontend.pages.LoginPage;
|
||||
import com.commafeed.frontend.pages.LogoutPage;
|
||||
@@ -59,6 +61,8 @@ public class CommaFeedApplication extends AuthenticatedWebApplication {
|
||||
mountPage("logout", LogoutPage.class);
|
||||
mountPage("error", DisplayExceptionPage.class);
|
||||
mountPage("favicon", FaviconPage.class);
|
||||
mountPage("google/import/redirect", GoogleImportRedirectPage.class);
|
||||
mountPage("google/import/callback", GoogleImportCallbackPage.class);
|
||||
|
||||
setupInjection();
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.commafeed.frontend.pages;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
import org.apache.wicket.request.Url;
|
||||
import org.apache.wicket.request.UrlRenderer;
|
||||
import org.apache.wicket.request.cycle.RequestCycle;
|
||||
import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import com.commafeed.backend.dao.ApplicationSettingsService;
|
||||
import com.commafeed.backend.dao.UserService;
|
||||
import com.commafeed.backend.feeds.OPMLImporter;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.frontend.utils.WicketUtils;
|
||||
import com.commafeed.frontend.utils.exception.DisplayException;
|
||||
import com.google.api.client.auth.oauth2.AuthorizationCodeResponseUrl;
|
||||
import com.google.api.client.auth.oauth2.AuthorizationCodeTokenRequest;
|
||||
import com.google.api.client.auth.oauth2.BearerToken;
|
||||
import com.google.api.client.auth.oauth2.TokenResponse;
|
||||
import com.google.api.client.http.GenericUrl;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class GoogleImportCallbackPage extends WebPage {
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Inject
|
||||
OPMLImporter importer;
|
||||
@Inject
|
||||
UserService userService;
|
||||
|
||||
private static final String TOKEN_URL = "https://accounts.google.com/o/oauth2/token";
|
||||
private static final String EXPORT_URL = "https://www.google.com/reader/subscriptions/export";
|
||||
|
||||
public static String getCallbackUrl() {
|
||||
RequestCycle cycle = RequestCycle.get();
|
||||
UrlRenderer renderer = cycle.getUrlRenderer();
|
||||
return renderer.renderFullUrl(Url.parse(cycle.urlFor(
|
||||
GoogleImportCallbackPage.class, null).toString()));
|
||||
}
|
||||
|
||||
public GoogleImportCallbackPage(PageParameters params) {
|
||||
|
||||
HttpServletRequest request = WicketUtils.getHttpServletRequest();
|
||||
StringBuffer urlBuffer = request.getRequestURL();
|
||||
if (request.getQueryString() != null) {
|
||||
urlBuffer.append('?').append(request.getQueryString());
|
||||
}
|
||||
AuthorizationCodeResponseUrl responseUrl = new AuthorizationCodeResponseUrl(
|
||||
urlBuffer.toString());
|
||||
String code = responseUrl.getCode();
|
||||
|
||||
if (responseUrl.getError() != null) {
|
||||
throw new DisplayException(responseUrl.getError());
|
||||
} else if (code == null) {
|
||||
throw new DisplayException("Missing authorization code");
|
||||
} else {
|
||||
ApplicationSettings settings = applicationSettingsService.get();
|
||||
String redirectUri = getCallbackUrl();
|
||||
String clientId = settings.getGoogleClientId();
|
||||
String clientSecret = settings.getGoogleClientSecret();
|
||||
|
||||
HttpTransport httpTransport = new NetHttpTransport();
|
||||
JacksonFactory jsonFactory = new JacksonFactory();
|
||||
|
||||
AuthorizationCodeTokenRequest tokenRequest = new AuthorizationCodeTokenRequest(
|
||||
httpTransport, jsonFactory, new GenericUrl(TOKEN_URL), code);
|
||||
tokenRequest.setRedirectUri(redirectUri);
|
||||
tokenRequest.put("client_id", clientId);
|
||||
tokenRequest.put("client_secret", clientSecret);
|
||||
tokenRequest.setGrantType("authorization_code");
|
||||
|
||||
try {
|
||||
TokenResponse tokenResponse = tokenRequest.execute();
|
||||
String accessToken = tokenResponse.getAccessToken();
|
||||
|
||||
HttpRequest httpRequest = httpTransport.createRequestFactory()
|
||||
.buildGetRequest(new GenericUrl(EXPORT_URL));
|
||||
BearerToken.authorizationHeaderAccessMethod().intercept(
|
||||
httpRequest, accessToken);
|
||||
String opml = httpRequest.execute().parseAsString();
|
||||
String state = responseUrl.getState();
|
||||
importer.importOpml(userService.findById(Long.valueOf(state)),
|
||||
opml);
|
||||
} catch (Exception e) {
|
||||
throw new DisplayException(e);
|
||||
}
|
||||
}
|
||||
setResponsePage(getApplication().getHomePage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.commafeed.frontend.pages;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
import org.apache.wicket.request.flow.RedirectToUrlException;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import com.commafeed.backend.dao.ApplicationSettingsService;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.frontend.CommaFeedSession;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class GoogleImportRedirectPage extends WebPage {
|
||||
|
||||
private static Logger log = Logger
|
||||
.getLogger(GoogleImportRedirectPage.class);
|
||||
|
||||
private static final String SCOPE = "https://www.google.com/reader/subscriptions/export";
|
||||
private static final String AUTH_URL = "https://accounts.google.com/o/oauth2/auth";
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
public GoogleImportRedirectPage() {
|
||||
|
||||
ApplicationSettings settings = applicationSettingsService.get();
|
||||
|
||||
String clientId = settings.getGoogleClientId();
|
||||
|
||||
String redirectUri = GoogleImportCallbackPage.getCallbackUrl();
|
||||
try {
|
||||
URIBuilder builder = new URIBuilder(AUTH_URL);
|
||||
|
||||
builder.addParameter("redirect_uri", redirectUri);
|
||||
builder.addParameter("response_type", "code");
|
||||
builder.addParameter("scope", SCOPE);
|
||||
builder.addParameter("approval_prompt", "force");
|
||||
builder.addParameter("client_id", clientId);
|
||||
builder.addParameter("state",
|
||||
String.valueOf(CommaFeedSession.get().getUser().getId()));
|
||||
|
||||
throw new RedirectToUrlException(builder.build().toString());
|
||||
} catch (URISyntaxException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import java.util.Set;
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.core.Application;
|
||||
|
||||
import com.commafeed.frontend.rest.resources.AdminSettingsREST;
|
||||
import com.commafeed.frontend.rest.resources.AdminUsersREST;
|
||||
import com.commafeed.frontend.rest.resources.EntriesREST;
|
||||
import com.commafeed.frontend.rest.resources.SessionREST;
|
||||
@@ -24,6 +25,7 @@ public class RESTApplication extends Application {
|
||||
set.add(EntriesREST.class);
|
||||
set.add(SettingsREST.class);
|
||||
set.add(AdminUsersREST.class);
|
||||
set.add(AdminSettingsREST.class);
|
||||
set.add(SessionREST.class);
|
||||
return set;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.commafeed.frontend.rest.resources;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import com.commafeed.backend.dao.ApplicationSettingsService;
|
||||
import com.commafeed.backend.model.ApplicationSettings;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
import com.commafeed.frontend.SecurityCheck;
|
||||
|
||||
@SecurityCheck(Role.ADMIN)
|
||||
@Path("admin/settings")
|
||||
public class AdminSettingsREST {
|
||||
|
||||
@Inject
|
||||
ApplicationSettingsService applicationSettingsService;
|
||||
|
||||
@Path("get")
|
||||
@GET
|
||||
public ApplicationSettings get() {
|
||||
return applicationSettingsService.get();
|
||||
}
|
||||
|
||||
@Path("save")
|
||||
@POST
|
||||
public Response save(ApplicationSettings settings) {
|
||||
applicationSettingsService.save(settings);
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,13 @@ package com.commafeed.frontend.utils.exception;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||
import org.apache.wicket.markup.html.WebPage;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
|
||||
|
||||
import de.agilecoders.wicket.Bootstrap;
|
||||
|
||||
public class DisplayExceptionPage extends WebPage {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -36,4 +39,9 @@ public class DisplayExceptionPage extends WebPage {
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderHead(IHeaderResponse response) {
|
||||
Bootstrap.renderHead(response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -492,4 +492,18 @@ module.controller('SettingsCtrl', function($scope, $location, SettingsService) {
|
||||
window.location.href.lastIndexOf('#'));
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('ManageSettingsCtrl', function($scope, $location, AdminSettingsService) {
|
||||
|
||||
$scope.settings = AdminSettingsService.get();
|
||||
|
||||
$scope.cancel = function() {
|
||||
$location.path('/');
|
||||
};
|
||||
$scope.save = function() {
|
||||
AdminSettingsService.save({}, $scope.settings, function() {
|
||||
$location.path('/');
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -39,6 +39,11 @@ app.config(function($routeProvider, $stateProvider, $urlRouterProvider) {
|
||||
templateUrl : 'templates/admin.useredit.html',
|
||||
controller : 'ManageUserCtrl'
|
||||
});
|
||||
$stateProvider.state('admin.settings', {
|
||||
url : '/settings',
|
||||
templateUrl : 'templates/admin.settings.html',
|
||||
controller : 'ManageSettingsCtrl'
|
||||
});
|
||||
|
||||
$stateProvider.state('settings', {
|
||||
url : '/settings',
|
||||
|
||||
@@ -211,4 +211,23 @@ module.factory('AdminUsersService', function($resource) {
|
||||
};
|
||||
var res = $resource('rest/admin/users/:_method', {}, actions);
|
||||
return res;
|
||||
});
|
||||
|
||||
module.factory('AdminSettingsService', function($resource) {
|
||||
var actions = {
|
||||
get : {
|
||||
method : 'GET',
|
||||
params : {
|
||||
_method : 'get'
|
||||
}
|
||||
},
|
||||
save : {
|
||||
method : 'POST',
|
||||
params : {
|
||||
_method : 'save'
|
||||
}
|
||||
}
|
||||
};
|
||||
var res = $resource('rest/admin/settings/:_method', {}, actions);
|
||||
return res;
|
||||
});
|
||||
@@ -57,7 +57,8 @@
|
||||
<form ng-upload class="form-horizontal" action="rest/subscriptions/import">
|
||||
<div class="modal-body">
|
||||
<div class="control-group">
|
||||
<span>Select the subscriptions.xml file you got from the zip file on google.com/takeout</span>
|
||||
<div>Download subscriptions.xml from <a target="_blank" href="https://www.google.com/reader/subscriptions/export">here</a>.</div>
|
||||
<div>Alternatively, let me import your feeds from your <a href="google/import/redirect">Google Reader account</a>.</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">XML File</label>
|
||||
|
||||
47
src/main/webapp/templates/admin.settings.html
Normal file
47
src/main/webapp/templates/admin.settings.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<div class="row">
|
||||
<div class="page-header">
|
||||
<h1>Application settings</h1>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form name="settingsForm" class="form-horizontal" ng-submit="save()">
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="publicUrl">Public URL</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="publicUrl" name="publicUrl"
|
||||
ng-model="settings.publicUrl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="allowRegistrations">Allow
|
||||
registrations</label>
|
||||
<div class="controls">
|
||||
<input type="checkbox" id="allowRegistrations"
|
||||
name="allowRegistrations" ng-model="settings.allowRegistrations" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="googleClientId">Google
|
||||
client ID</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="googleClientId"
|
||||
ng-model="settings.googleClientId" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="googleClientSecret">Google
|
||||
client secret</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="googleClientSecret"
|
||||
ng-model="settings.googleClientSecret" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<button type="button" class="btn" ng-click="cancel()">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user