Package org.fluxtream.core.services.impl

Source Code of org.fluxtream.core.services.impl.GuestServiceImpl

package org.fluxtream.core.services.impl;

import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService;
import net.sf.json.JSONObject;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.impl.client.DefaultHttpClient;
import org.fluxtream.core.Configuration;
import org.fluxtream.core.aspects.FlxLogger;
import org.fluxtream.core.auth.FlxUserDetails;
import org.fluxtream.core.connectors.Connector;
import org.fluxtream.core.connectors.OAuth2Helper;
import org.fluxtream.core.connectors.location.LocationFacet;
import org.fluxtream.core.domain.*;
import org.fluxtream.core.services.*;
import org.fluxtream.core.utils.*;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.io.IOException;
import java.util.*;

@Service
@Transactional(readOnly=true)
public class GuestServiceImpl implements GuestService, DisposableBean {

    static FlxLogger logger = FlxLogger.getLogger(GuestServiceImpl.class);

    @Autowired
    BodyTrackHelper bodyTrackHelper;

  @Autowired
  Configuration env;

  @PersistenceContext
  EntityManager em;

    @Qualifier("apiDataServiceImpl")
    @Autowired
  ApiDataService apiDataService;

    @Qualifier("metadataServiceImpl")
    @Autowired
  MetadataService metadataService;

    @Qualifier("connectorUpdateServiceImpl")
    @Autowired
  ConnectorUpdateService connectorUpdateService;

    @Autowired
    OAuth2Helper oAuth2Helper;

    @Autowired
    @Qualifier("AsyncWorker")
    ThreadPoolTaskExecutor executor;

    @Autowired
    BeanFactory beanFactory;

    @Autowired
    SystemService systemService;

    @Autowired
    SettingsService settingsService;

  LookupService geoIpLookupService;

  private final RandomString randomString = new RandomString(64);

  private UserDetails loadUserByUsername(String username)
      throws UsernameNotFoundException {
    final Guest guest = JPAUtils.findUnique(em, Guest.class,
        "guest.byUsername", username);
    if (guest == null)
      return null;
        return new FlxUserDetails(guest);
  }

  public UserDetails loadUserByEmail(String email)
      throws UsernameNotFoundException {
    final Guest guest = JPAUtils.findUnique(em, Guest.class,
        "guest.byEmail", email);
    if (guest == null)
      return null;
        return new FlxUserDetails(guest);
  }

  @Transactional(readOnly = false)
  public Guest createGuest(String username, String firstname, String lastname,
                             String password, String email, Guest.RegistrationMethod registrationMethod,
                             final String appId)
            throws UsernameAlreadyTakenException, ExistingEmailException
    {
    if (loadUserByUsername(username) != null)
      throw new UsernameAlreadyTakenException(username + " is already taken");
    if (loadUserByEmail(email) != null)
      throw new ExistingEmailException(email + " is already used");
    Guest guest = new Guest();
    guest.username = username;
    guest.email = email;
    guest.firstname = firstname;
    guest.lastname = lastname;
        guest.registrationMethod = registrationMethod;
        guest.setRoles("ROLE_USER");
        if (password!=null)
        setPassword(guest, password);
        if (appId!=null) {
            // enforce API registration method
            guest.registrationMethod = Guest.RegistrationMethod.REGISTRATION_METHOD_API;
            guest.appId = appId;
        }
    em.persist(guest);

    return guest;
  }

  private void setPassword(Guest guest, String password) {
    ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder();
    String salt = randomString.nextString();
    guest.salt = salt;
        if (guest.registrationMethod == Guest.RegistrationMethod.REGISTRATION_METHOD_FACEBOOK)
            guest.registrationMethod = Guest.RegistrationMethod.REGISTRATION_METHOD_FACEBOOK_WITH_PASSWORD;
    guest.password = passwordEncoder.encodePassword(password, salt);
  }

  @Override
  @Transactional(readOnly = false)
  public void setPassword(long guestId, String password) {
    Guest guest = getGuestById(guestId);
    setPassword(guest, password);
    em.persist(guest);
  }

    @Override
    @Transactional(readOnly=false)
    public ApiKey createApiKey(final long guestId, final Connector connector) {
        ApiKey apiKey = new ApiKey();
        apiKey.setGuestId(guestId);
        apiKey.setConnector(connector);
        em.persist(apiKey);
        populateApiKey(apiKey.getId());
        return apiKey;
    }

    @Override
    @Transactional(readOnly=false)
    public void populateApiKey(final long apiKeyId) {
        ConnectorInfo connectorInfo = null;
        ApiKey apiKey = getApiKey(apiKeyId);
        try { connectorInfo = systemService.getConnectorInfo(apiKey.getConnector().getName());
        } catch (Throwable e) {}
        if (connectorInfo == null || !connectorInfo.enabled)
            throw new RuntimeException("This connector is not enabled!");
        final String[] apiKeyAttributesKeys = connectorInfo.getApiKeyAttributesKeys();
        if(apiKeyAttributesKeys!=null) {
            for (String key : apiKeyAttributesKeys) {
                if (env.get(key)==null)
                    throw new RuntimeException("No value was found for key :" + key + ". Cannot create apiKey");
                setApiKeyAttribute(apiKey, key, env.get(key));
            }
        }
    }

    @Override
    @Transactional(readOnly=false)
    public void addDeveloperRole(Long guestId) {
        Guest guest = getGuestById(guestId);
        if (guest.hasRole("ROLE_DEVELOPER"))
            return;
        List<String> userRoles = guest.getUserRoles();
        userRoles.add("ROLE_DEVELOPER");
        persistUserRoles(guest, userRoles);
    }

    @Override
    @Transactional(readOnly=false)
    public void deleteConnectorProfile(final ApiKey apiKey) {
        Class<? extends AbstractUserProfile> userProfileClass = apiKey.getConnector()
                .userProfileClass();
        if (userProfileClass != null
                && userProfileClass != AbstractUserProfile.class) {
            Query deleteProfileQuery = em.createQuery("DELETE FROM "
                    + userProfileClass.getName() + " WHERE apiKeyId=" + apiKey.getId());
            deleteProfileQuery.executeUpdate();
        }
    }

    @Override
  public Guest getGuest(String username) {
        return JPAUtils.findUnique(em, Guest.class,
                "guest.byUsername", username);
  }

  @Override
  public boolean isUsernameAvailable(String username) {
    final Guest guest = JPAUtils.findUnique(em, Guest.class,
        "guest.byUsername", username);
    return guest == null;
  }

  @Override
  public Guest getGuestById(long id) {
    return em.find(Guest.class, id);
  }

  @Override
  @Transactional(readOnly = false)
  public ApiKey setApiKeyAttribute(ApiKey ak, String key,
      String value) {
        ApiKey apiKey = em.find(ApiKey.class, ak.getId(), LockModeType.PESSIMISTIC_WRITE);

        // apiKey could be null, for example if the connector
        // was already deleted.  In this case just return
        // null
        if(apiKey==null) {
            return null;
        }
        // At this point we know that apiKey exists and
        // is non-null
        apiKey.removeAttribute(key);
        ApiKeyAttribute attr = new ApiKeyAttribute();
    attr.attributeKey = key;
    attr.setAttributeValue(value, env);
    em.persist(attr);
    apiKey.setAttribute(attr);
        em.merge(apiKey);
    return apiKey;
  }

    @Override
    public Map<String, String> getApiKeyAttributes(final long apiKeyId) {
        ApiKey apiKey = em.find(ApiKey.class, apiKeyId);
        final Map<String, String> attributes = apiKey.getAttributes(env);
        return attributes;
    }

  @Override
    @Transactional(readOnly = false)
  public void removeApiKey(long apiKeyId) {
    ApiKey apiKey = em.find(ApiKey.class, apiKeyId);

        // apiKey could be null, for example if the connector
        // was already deleted.  In this case just return
        if(apiKey==null) {
            return;
        }

        final String refreshTokenRemoveURL = apiKey.getAttributeValue("refreshTokenRemoveURL", env);
        // Revoke refresh token might throw.  If it does we still want to remove the apiKeys from
        // the DB which is why we put it in a try/finally block
        try {
             if (refreshTokenRemoveURL !=null)
                oAuth2Helper.revokeRefreshToken(apiKey.getGuestId(), apiKey.getConnector(), refreshTokenRemoveURL);
        }
        finally {
            em.remove(apiKey);
            // cleanup the data asynchrously in order not to block the user's flow
            bodyTrackHelper.deleteChannelMappings(apiKey);
            ApiDataCleanupWorker worker = beanFactory.getBean(ApiDataCleanupWorker.class);
            worker.setApiKey(apiKey);
            executor.execute(worker);
        }
  }

    @Override
    @Deprecated
  public String getApiKeyAttribute(ApiKey ak, String key) {
        ApiKey apiKey = em.find(ApiKey.class, ak.getId());
        // apiKey could be null, for example if the connector
        // was deleted.  In this case return null
        if(apiKey!=null) {
        return apiKey.getAttributeValue(key, env);
        }
        else {
            return null;
        }
  }

    @Override
    public ApiKey getApiKey(final long apiKeyId) {
        return em.find(ApiKey.class, apiKeyId);
    }

    @Override
  public List<ApiKey> getApiKeys(long guestId) {
        // rawKeys includes all the keys in the apiKeys table for a given guest.
        // However, it's potentially the case that this could include keys which
        // do not currently map to valid entries in the Connector table.
        // We can test for that condition by checking if key.getConnector() returns
        // null.  Include only the keys which return non-null in goodKeys and return.
        List<ApiKey> rawKeys = JPAUtils.find(em, ApiKey.class, "apiKeys.all",
                    guestId);
        List<ApiKey> goodKeys = new ArrayList<ApiKey>();
        for (ApiKey key : rawKeys){
            if(key.getConnector()!=null) {
                goodKeys.add(key);
            }
        }
        return(goodKeys);
  }

  @Override
  public boolean hasApiKey(long guestId, Connector api) {
        assert api!=null : "api must not be null";
    ApiKey apiKey = JPAUtils.findUnique(em, ApiKey.class, "apiKey.byApi",
        guestId, api.value());
    return (apiKey != null);
  }

  @Override
  public List<ApiKey> getApiKeys(long guestId, Connector api) {
        List<ApiKey> apiKeys = JPAUtils.find(em, ApiKey.class, "apiKey.byApi", guestId, api.value());
        Collections.sort(apiKeys, new Comparator<ApiKey>() {
            @Override
            public int compare(ApiKey o1, ApiKey o2) {
                return (int)(o2.getId()-o1.getId());
            }
        });
        return apiKeys;
  }

    @Override
    @Transactional(readOnly=false)
    public void setApiKeyStatus(final long apiKeyId, final ApiKey.Status status, final String stackTrace,
                                final String reason) {
        final ApiKey apiKey = getApiKey(apiKeyId);
        if (apiKey!=null) {
            apiKey.status = status;
            if (status== ApiKey.Status.STATUS_UP) {
                apiKey.stackTrace = null;
                apiKey.reason = null;
            } else {
                if (stackTrace != null)
                    apiKey.stackTrace = stackTrace;
                if (reason != null)
                    apiKey.reason = reason;
            }
            em.persist(apiKey);
        }
    }

    @Override
    @Transactional(readOnly=false)
    public void setApiKeyToSynching(final long apiKeyId, final boolean synching) {
        final ApiKey apiKey = getApiKey(apiKeyId);
        if (apiKey!=null) {
            apiKey.synching = synching;
            em.persist(apiKey);
        }
    }

    @Override
    @Deprecated
    public ApiKey getApiKey(long guestId, Connector api) {
        List<ApiKey> apiKeys = getApiKeys(guestId, api);
        return apiKeys.size()>0
                ? apiKeys.get(0)
                : null;
    }

    @Override
    @Transactional(readOnly=false)
    public void removeApiKeys(final long guestId, final Connector connector) {
        final List<ApiKey> apiKeys = getApiKeys(guestId, connector);
        for (ApiKey apiKey : apiKeys)
            removeApiKey(apiKey.getId());
    }

    @Override
    @Transactional(readOnly = false)
    public void eraseGuestInfo(long id) throws Exception {
        Guest guest = getGuestById(id);
        if (guest == null)
            return;
        if (guest.registrationMethod==Guest.RegistrationMethod.REGISTRATION_METHOD_FACEBOOK||
            guest.registrationMethod==Guest.RegistrationMethod.REGISTRATION_METHOD_FACEBOOK_WITH_PASSWORD) {
            revokeFacebookPermissions(guest);
        }
        JPAUtils.execute(em, "updateWorkerTasks.delete.all", guest.getId());
        em.remove(guest);
        List<ApiKey> apiKeys = getApiKeys(guest.getId());
        for (ApiKey key : apiKeys) {
            if(key!=null && key.getConnector()!=null) {
                apiDataService.eraseApiData(key);
            }
        }
        for (ApiKey apiKey : apiKeys) {
            if(apiKey!=null){
                em.remove(apiKey);
            }
        }
        JPAUtils.execute(em, "addresses.delete.all", guest.getId());
        JPAUtils.execute(em, "notifications.delete.all", guest.getId());
        JPAUtils.execute(em, "settings.delete.all", guest.getId());
        JPAUtils.execute(em, "location.delete.all", guest.getId());
        JPAUtils.execute(em, "visitedCities.delete.all", guest.getId());
        JPAUtils.execute(em, "updateWorkerTasks.delete.all", guest.getId());
        JPAUtils.execute(em, "tags.delete.all", guest.getId());
        JPAUtils.execute(em, "notifications.delete.all", guest.getId());
        final List<CoachingBuddy> coachingBuddies = JPAUtils.find(em, CoachingBuddy.class, "coachingBuddies.byGuestId", guest.getId());
        for (CoachingBuddy coachingBuddy : coachingBuddies)
            em.remove(coachingBuddy);
        JPAUtils.execute(em, "channelMapping.delete.all", guest.getId());
        JPAUtils.execute(em, "connectorFilterState.delete.all", guest.getId());
        JPAUtils.execute(em, "channelStyle.delete.all", guest.getId());
        JPAUtils.execute(em, "grapherView.delete.all", guest.getId());
        JPAUtils.execute(em, "widgetSettings.delete.all", guest.getId());
        JPAUtils.execute(em, "dashboards.delete.all", guest.getId());
    }

    private void revokeFacebookPermissions(final Guest guest) {
        ApiKey facebookApiKey = getApiKey(guest.getId(), Connector.getConnector("facebook"));
        final String meString = getApiKeyAttribute(facebookApiKey, "me");
        final String accessToken = getApiKeyAttribute(facebookApiKey, "accessToken");
        JSONObject meJSON = JSONObject.fromObject(meString);
        String id = meJSON.getString("id");
        HttpClient client = new DefaultHttpClient();
        try {
            final String uri = String.format("https://graph.facebook.com/%s/permissions?access_token=%s", id, accessToken);
            HttpDelete delete = new HttpDelete(uri);
            client.execute(delete);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            client.getConnectionManager().shutdown();
        }
    }

    @Override
  @Transactional(readOnly = false)
    @Secured("ROLE_ADMIN")
  public void eraseGuestInfo(String username) throws Exception {
        Guest guest = getGuest(username);
        eraseGuestInfo(guest.getId());
  }

  @Override
  public List<Guest> getAllGuests() {
    List<Guest> all = JPAUtils.find(em, Guest.class, "guests.all",
        (Object[]) null);
    List<Guest> result = new ArrayList<Guest>();
    for (Guest guest : all)
      result.add(guest);
    return result;
  }

  @Override
  @Transactional(readOnly = false)
  @Secured("ROLE_ADMIN")
  public void addRole(long guestId, String role) {
    Guest guest = getGuestById(guestId);
    if (guest.hasRole(role))
      return;
    List<String> userRoles = guest.getUserRoles();
    userRoles.add(role);
    persistUserRoles(guest, userRoles);
  }

  @Override
  @Transactional(readOnly = false)
  @Secured("ROLE_ADMIN")
  public void removeRole(long guestId, String role) {
    Guest guest = getGuestById(guestId);
    if (!guest.hasRole(role))
      return;
    List<String> userRoles = guest.getUserRoles();
    userRoles.remove(role);
    persistUserRoles(guest, userRoles);
  }

  private void persistUserRoles(Guest guest, List<String> userRoles) {
    StringBuffer roles = new StringBuffer();
    for (int i = 0; i < userRoles.size(); i++) {
      if (i > 0)
        roles.append(",");
      roles.append(userRoles.get(i));
    }
    guest.setRoles(roles.toString());
    em.persist(guest);
  }

    @Override
    @Transactional(readOnly=false)
    public void setApiKeySettings(final long apiKeyId, final Object settings) {
        ApiKey apiKey = getApiKey(apiKeyId);
        apiKey.setSettings(settings);
        em.persist(apiKey);
    }

    @Override
    @Transactional(readOnly=false)
    public void removeApiKeyAttribute(final long apiKeyId, final String key) {
        ApiKey apiKey = getApiKey(apiKeyId);
        apiKey.removeAttribute(key);
        em.persist(apiKey);
    }

    @Override
    @Transactional(readOnly=false)
    public void setAutoLoginToken(final long guestId, final String s) {
        Guest guest = getGuestById(guestId);
        guest.autoLoginToken = s;
        guest.autoLoginTokenTimestamp = System.currentTimeMillis();
        em.persist(guest);
    }

    @Override
    public boolean checkPassword(final long guestId, final String currentPassword) {
        Guest guest = getGuestById(guestId);
        ShaPasswordEncoder passwordEncoder = new ShaPasswordEncoder();
        String password = passwordEncoder.encodePassword(currentPassword, guest.salt);
        return password.equals(guest.password);
    }

    @Override
  public ResetPasswordToken getToken(String token) {
        return JPAUtils.findUnique(em,
                ResetPasswordToken.class, "passwordToken.byToken", token);
  }

  @Override
  @Transactional(readOnly = false)
  public ResetPasswordToken createToken(long guestId) {
    ResetPasswordToken pToken = new ResetPasswordToken();
    pToken.guestId = guestId;
    pToken.token = randomString.nextString();
    pToken.ts = System.currentTimeMillis();
    em.persist(pToken);
    return pToken;
  }

  @Override
  public Guest getGuestByEmail(String email) {
        return JPAUtils.findUnique(em, Guest.class,
                "guest.byEmail", email);
  }

  @Override
  public void deleteToken(String token) {
    ResetPasswordToken ptoken = JPAUtils.findUnique(em,
        ResetPasswordToken.class, "passwordToken.byToken", token);
    em.remove(ptoken);
  }

  @Override
  public void checkIn(long guestId, String ipAddress) throws IOException {
    if (SecurityUtils.isStealth())
      return;
    if (geoIpLookupService == null) {
      String dbLocation = env.get("geoIpDb.location");
      geoIpLookupService = new LookupService(dbLocation,
          LookupService.GEOIP_MEMORY_CACHE);
    }

        LocationFacet locationFacet = new LocationFacet(1);
        long time = System.currentTimeMillis();
        locationFacet.guestId = guestId;
        locationFacet.timestampMs = time;
        locationFacet.start = time;
        locationFacet.end = time;
        locationFacet.guestId = guestId;

        // Set both api and apiKeyId fields to zero since this location is not coming from a connector
        locationFacet.api = 0;
        locationFacet.apiKeyId = 0L;

        Location ipLocation = null;
        try {
        ipLocation = geoIpLookupService.getLocation(ipAddress);
        } catch (Throwable t) {
            StringBuilder sb = new StringBuilder("module=web component=guestServiceImpl action=checkIn")
                    .append(" guestId=").append(guestId).append(" message=" + t.getMessage());
            logger.info(sb.toString());
        }
    if (ipLocation != null) {
            locationFacet.accuracy = 7000;
            locationFacet.latitude = ipLocation.latitude;
            locationFacet.longitude = ipLocation.longitude;
            locationFacet.source = LocationFacet.Source.GEO_IP_DB;
            apiDataService.addGuestLocation(guestId,
          locationFacet);
    } else if (env.get("environment").equals("local")) {
            try{
                locationFacet.accuracy = 7000;
                locationFacet.latitude = env.getFloat("defaultLocation.latitude");
                locationFacet.longitude = env.getFloat("defaultLocation.longitude");
                locationFacet.source = LocationFacet.Source.OTHER;
                apiDataService.addGuestLocation(guestId,
                        locationFacet);
            }
            catch (Exception ignored){
            }
    } else if (env.get("ip2location.apiKey")!=null) {
            String ip2locationKey = env.get("ip2location.apiKey");
            String jsonString;
            try {
                jsonString = HttpUtils.fetch("http://api.ipinfodb.com/v3/ip-city/?key=" + ip2locationKey + "&ip=" + ipAddress + "&format=json");
            }
            catch (UnexpectedHttpResponseCodeException e) {
                // simply log the error and don't persist anything to the guest location table
                logger.warn(String.format("ip2location http error; code is %s, message is '%s'", e.getHttpResponseCode(),
                                          e.getHttpResponseMessage()));
                return;
            }
            JSONObject json = JSONObject.fromObject(jsonString);
      String latitude = json.getString("latitude");
      String longitude = json.getString("longitude");
            locationFacet.latitude = Float.valueOf(latitude);
            locationFacet.longitude = Float.valueOf(longitude);
            if (latitude != null && longitude != null) {
        float lat = Float.valueOf(latitude);
        float lon = Float.valueOf(longitude);
                locationFacet.accuracy = 7000;
                locationFacet.latitude = lat;
                locationFacet.longitude = lon;
                locationFacet.source = LocationFacet.Source.IP_TO_LOCATION;
                apiDataService.addGuestLocation(guestId,
            locationFacet);
      }
    }
  }

    @Override
    public void destroy() throws Exception {
        executor.shutdown();
    }
}
TOP

Related Classes of org.fluxtream.core.services.impl.GuestServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.