import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.utils.System2;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.resource.ResourceDao;
public void load_component_id_from_db() throws Exception {
setupData("load_component_id_from_db");
- ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+ ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
assertThat(componentId).isEqualTo(123);
public void fail_to_load_component_id_if_unknown_component() throws Exception {
setupData("empty");
- ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+ ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
try {
storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
fail();
public void load_project_id_from_db() throws Exception {
setupData("load_project_id_from_db");
- ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+ ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
long projectId = storage.projectId(new DefaultIssue().setProjectKey("struts"));
assertThat(projectId).isEqualTo(1);
public void fail_to_load_project_id_if_unknown_component() throws Exception {
setupData("empty");
- ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis()));
+ ServerIssueStorage storage = new ServerIssueStorage(getMyBatis(), new FakeRuleFinder(), new ResourceDao(getMyBatis(), System2.INSTANCE));
try {
storage.projectId(new DefaultIssue().setProjectKey("struts"));
fail();
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
import org.sonar.core.persistence.TestDatabase;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.SnapshotDto;
@Before
public void before() {
- executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis()));
+ executor = new MeasureFilterExecutor(db.myBatis(), db.database(), new ResourceDao(db.myBatis(), System2.INSTANCE));
}
@Test
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.utils.System2;
import org.sonar.batch.ProjectTree;
import org.sonar.batch.index.SnapshotCache;
import org.sonar.core.persistence.AbstractDaoTestCase;
@Before
public void setUp() throws Exception {
- storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()), projectTree);
+ storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis(), System2.INSTANCE), projectTree);
}
@Test
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.user.GroupDto;
-import org.sonar.core.user.GroupRoleDto;
-import org.sonar.core.user.RoleDao;
-import org.sonar.core.user.UserDao;
-import org.sonar.core.user.UserRoleDto;
+import org.sonar.core.user.*;
import javax.annotation.Nullable;
this.settings = settings;
}
- public void insertUserPermission(@Nullable Long resourceId, Long userId, String permission, @Nullable SqlSession session) {
+ private void insertUserPermission(@Nullable Long resourceId, Long userId, String permission, boolean updateProjectAuthorizationDate, @Nullable SqlSession session) {
UserRoleDto userRoleDto = new UserRoleDto()
.setRole(permission)
.setUserId(userId)
.setResourceId(resourceId);
+ if (updateProjectAuthorizationDate) {
+ updateProjectAuthorizationDate(resourceId, session);
+ }
if (session != null) {
roleDao.insertUserRole(userRoleDto, session);
} else {
}
}
+ public void insertUserPermission(@Nullable Long resourceId, Long userId, String permission, @Nullable SqlSession session) {
+ insertUserPermission(resourceId, userId, permission, true, session);
+ }
+
public void insertUserPermission(@Nullable Long resourceId, Long userId, String permission) {
insertUserPermission(resourceId, userId, permission, null);
}
.setRole(permission)
.setUserId(userId)
.setResourceId(resourceId);
+ updateProjectAuthorizationDate(resourceId, session);
if (session != null) {
roleDao.deleteUserRole(userRoleDto, session);
} else {
deleteUserPermission(resourceId, userId, permission, null);
}
- public void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission, @Nullable SqlSession session) {
+ private void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission, boolean updateProjectAuthorizationDate, @Nullable SqlSession session) {
GroupRoleDto groupRole = new GroupRoleDto()
.setRole(permission)
.setGroupId(groupId)
.setResourceId(resourceId);
+ updateProjectAuthorizationDate(resourceId, session);
if (session != null) {
roleDao.insertGroupRole(groupRole, session);
} else {
}
}
+ private void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission, @Nullable SqlSession session) {
+ insertGroupPermission(resourceId, groupId, permission, true, session);
+ }
+
public void insertGroupPermission(@Nullable Long resourceId, @Nullable Long groupId, String permission) {
insertGroupPermission(resourceId, groupId, permission, null);
}
.setRole(permission)
.setGroupId(groupId)
.setResourceId(resourceId);
+ updateProjectAuthorizationDate(resourceId, session);
if (session != null) {
roleDao.deleteGroupRole(groupRole, session);
} else {
}
}
+ /**
+ * For each modification of permission on a project, update the authorization_updated_at to help ES reindex only relevant changes
+ */
+ private void updateProjectAuthorizationDate(@Nullable Long projectId, @Nullable SqlSession session){
+ if (projectId != null) {
+ if (session != null) {
+ resourceDao.updateAuthorizationDate(projectId, session);
+ } else {
+ resourceDao.updateAuthorizationDate(projectId);
+ }
+ }
+ }
+
/**
* Load permission template and load associated collections of users and groups permissions
*/
PermissionTemplateDto permissionTemplate = getPermissionTemplateWithPermissions(templateKey);
SqlSession session = myBatis.openSession(false);
try {
+ updateProjectAuthorizationDate(resourceId, session);
removeAllPermissions(resourceId, session);
List<PermissionTemplateUserDto> usersPermissions = permissionTemplate.getUsersPermissions();
if (usersPermissions != null) {
for (PermissionTemplateUserDto userPermission : usersPermissions) {
- insertUserPermission(resourceId, userPermission.getUserId(), userPermission.getPermission(), session);
+ insertUserPermission(resourceId, userPermission.getUserId(), userPermission.getPermission(), false, session);
}
}
List<PermissionTemplateGroupDto> groupsPermissions = permissionTemplate.getGroupsPermissions();
if (groupsPermissions != null) {
for (PermissionTemplateGroupDto groupPermission : groupsPermissions) {
Long groupId = groupPermission.getGroupId() == null ? null : groupPermission.getGroupId();
- insertGroupPermission(resourceId, groupId, groupPermission.getPermission(), session);
+ insertGroupPermission(resourceId, groupId, groupPermission.getPermission(), false, session);
}
}
session.commit();
return roleDao.countResourceGroupRoles(resourceId) + roleDao.countResourceUserRoles(resourceId);
}
- public void removeAllPermissions(Long resourceId, SqlSession session) {
+ protected void removeAllPermissions(Long resourceId, SqlSession session) {
roleDao.deleteGroupRolesByResourceId(resourceId, session);
roleDao.deleteUserRolesByResourceId(resourceId, session);
}
import com.google.common.collect.Lists;
import org.apache.ibatis.session.SqlSession;
import org.sonar.api.component.Component;
+import org.sonar.api.utils.System2;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DbSession;
public class ResourceDao implements DaoComponent {
private MyBatis mybatis;
+ private System2 system2;
- public ResourceDao(MyBatis mybatis) {
+ public ResourceDao(MyBatis mybatis, System2 system2) {
this.mybatis = mybatis;
+ this.system2 = system2;
}
public List<ResourceDto> getResources(ResourceQuery query) {
public ResourceDao insertOrUpdate(ResourceDto... resources) {
SqlSession session = mybatis.openSession(false);
ResourceMapper mapper = session.getMapper(ResourceMapper.class);
+ Date now = new Date(system2.now());
try {
for (ResourceDto resource : resources) {
if (resource.getId() == null) {
- resource.setCreatedAt(new Date());
+ resource.setCreatedAt(now);
+ resource.setAuthorizationUpdatedAt(now);
mapper.insert(resource);
} else {
mapper.update(resource);
return this;
}
+ public void updateAuthorizationDate(Long projectId, SqlSession session) {
+ session.getMapper(ResourceMapper.class).updateAuthorizationDate(projectId, new Date(system2.now()));
+ }
+
+ /**
+ * Should not be called from batch side (used to reindex permission in E/S)
+ */
+ public void updateAuthorizationDate(Long projectId) {
+ SqlSession session = mybatis.openSession(false);
+ try {
+ updateAuthorizationDate(projectId, session);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
public Collection<ComponentDto> selectComponentsByIds(Collection<Long> ids) {
if (ids.isEmpty()) {
return Collections.emptyList();
private Long copyResourceId;
private Long personId;
private Date createdAt;
+ private Date authorizationUpdatedAt;
public Long getId() {
return id;
this.createdAt = date;// NOSONAR May expose internal representation by incorporating reference to mutable object
return this;
}
+
+ public Date getAuthorizationUpdatedAt() {
+ return authorizationUpdatedAt;
+ }
+
+ public ResourceDto setAuthorizationUpdatedAt(Date authorizationUpdatedAt) {
+ this.authorizationUpdatedAt = authorizationUpdatedAt;
+ return this;
+ }
}
import javax.annotation.Nullable;
import java.util.Collection;
+import java.util.Date;
import java.util.List;
public interface ResourceMapper {
void update(ResourceDto resource);
+ void updateAuthorizationDate(@Param("projectId") Long projectId, @Param("authorizationDate") Date authorizationDate);
+
}
p.language as language,
p.copy_resource_id as copyResourceId,
p.person_id as personId,
- p.created_at as createdAt
+ p.created_at as createdAt,
+ p.authorization_updated_at as authorizationUpdatedAt
</sql>
<sql id="componentColumns">
<result property="copyResourceId" column="copy_resource_id"/>
<result property="personId" column="person_id"/>
<result property="createdAt" column="created_at"/>
+ <result property="authorizationUpdatedAt" column="authorization_updated_at"/>
</resultMap>
<select id="selectResources" parameterType="map" resultMap="resourceResultMap">
<insert id="insert" parameterType="Resource" keyColumn="id" useGeneratedKeys="true" keyProperty="id" >
insert into projects
- (name, long_name, description, scope, qualifier, kee, deprecated_kee, path, language, root_id, copy_resource_id, person_id, enabled, created_at)
+ (name, long_name, description, scope, qualifier, kee, deprecated_kee, path, language, root_id, copy_resource_id, person_id, enabled, authorization_updated_at, created_at)
values (
#{name}, #{longName}, #{description}, #{scope}, #{qualifier},
#{key}, #{deprecatedKey}, #{path}, #{language}, #{rootId}, #{copyResourceId},
- #{personId}, #{enabled}, #{createdAt}
+ #{personId}, #{enabled}, #{authorizationUpdatedAt}, #{createdAt}
)
</insert>
language=#{language}, root_id=#{rootId}, copy_resource_id=#{copyResourceId},
person_id=#{personId}, enabled=#{enabled} where id=#{id}
</update>
+
+ <update id="updateAuthorizationDate" parameterType="map">
+ update projects set authorization_updated_at=#{authorizationDate}
+ <where>
+ AND id=#{projectId}
+ </where>
+ </update>
+
</mapper>
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.Settings;
+import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.core.persistence.AbstractDaoTestCase;
@Rule
public ExpectedException throwable = ExpectedException.none();
+ private System2 system2;
private PermissionFacade permissionFacade;
private PermissionTemplateDao permissionTemplateDao;
+ private ResourceDao resourceDao;
@Before
public void setUp() {
+ system2 = mock(System2.class);
+ when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-03").getTime());
+
RoleDao roleDao = new RoleDao(getMyBatis());
UserDao userDao = new UserDao(getMyBatis());
permissionTemplateDao = new PermissionTemplateDao(getMyBatis(), System2.INSTANCE);
Settings settings = new Settings();
- permissionFacade = new PermissionFacade(getMyBatis(), roleDao, userDao, new ResourceDao(getMyBatis()), permissionTemplateDao, settings);
+ resourceDao = new ResourceDao(getMyBatis(), system2);
+ permissionFacade = new PermissionFacade(getMyBatis(), roleDao, userDao, resourceDao, permissionTemplateDao, settings);
}
@Test
assertThat(permissionFacade.selectGroupPermissions("Anyone", 123L)).containsOnly("user", "codeviewer");
assertThat(permissionFacade.selectUserPermissions("marius", 123L)).containsOnly("admin");
+
+ assertThat(resourceDao.getResource(123L).getAuthorizationUpdatedAt()).isEqualTo(DateUtils.parseDate("2014-09-03"));
}
@Test
permissionFacade.insertUserPermission(123L, 200L, UserRole.ADMIN);
checkTable("should_add_user_permission", "user_roles", "user_id", "resource_id", "role");
+ checkTable("should_add_user_permission", "projects", "authorization_updated_at");
}
@Test
permissionFacade.deleteUserPermission(123L, 200L, UserRole.ADMIN);
checkTable("should_delete_user_permission", "user_roles", "user_id", "resource_id", "role");
+ checkTable("should_delete_user_permission", "projects", "authorization_updated_at");
}
@Test
}
checkTable("should_insert_group_permission", "group_roles", "group_id", "resource_id", "role");
+ checkTable("should_insert_group_permission", "projects", "authorization_updated_at");
}
@Test
}
checkTable("should_insert_group_permission", "group_roles", "group_id", "resource_id", "role");
+ checkTable("should_insert_group_permission", "projects", "authorization_updated_at");
}
@Test
}
checkTable("should_insert_anyone_group_permission", "group_roles", "group_id", "resource_id", "role");
+ checkTable("should_insert_anyone_group_permission", "projects", "authorization_updated_at");
}
@Test
permissionFacade.deleteGroupPermission(123L, 100L, UserRole.USER);
checkTable("should_delete_group_permission", "group_roles", "group_id", "resource_id", "role");
+ checkTable("should_delete_group_permission", "projects", "authorization_updated_at");
}
@Test
}
checkTable("should_delete_group_permission", "group_roles", "group_id", "resource_id", "role");
+ checkTable("should_delete_group_permission", "projects", "authorization_updated_at");
}
@Test
system2 = mock(System2.class);
when(system2.now()).thenReturn(DateUtils.parseDate("2014-04-09").getTime());
- dao = new PurgeDao(getMyBatis(), new ResourceDao(getMyBatis()), new PurgeProfiler());
+ dao = new PurgeDao(getMyBatis(), new ResourceDao(getMyBatis(), system2), new PurgeProfiler());
}
@Test
project = new Project("project").setId(PROJECT_ID.intValue());
settings = new Settings();
permissionFacade = new PermissionFacade(getMyBatis(),
- new RoleDao(getMyBatis()), new UserDao(getMyBatis()), new ResourceDao(getMyBatis()), new PermissionTemplateDao(getMyBatis(), System2.INSTANCE), settings);
+ new RoleDao(getMyBatis()), new UserDao(getMyBatis()), new ResourceDao(getMyBatis(), System2.INSTANCE), new PermissionTemplateDao(getMyBatis(), System2.INSTANCE), settings);
permissions = new DefaultResourcePermissions(getMyBatis(), permissionFacade);
}
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.persistence.DbSession;
import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class ResourceDaoTest extends AbstractDaoTestCase {
private DbSession session;
private ResourceDao dao;
+ private System2 system2;
@Before
public void createDao() {
session = getMyBatis().openSession(false);
- dao = new ResourceDao(getMyBatis());
+ system2 = mock(System2.class);
+ when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-03").getTime());
+ dao = new ResourceDao(getMyBatis(), system2);
}
@After
assertThat(resource.getDescription()).isEqualTo("the description");
assertThat(resource.getLanguage()).isEqualTo("java");
assertThat(resource.isEnabled()).isTrue();
+ assertThat(resource.getAuthorizationUpdatedAt()).isNotNull();
+ assertThat(resource.getCreatedAt()).isNotNull();
}
@Test
assertThat(file1.getId()).isNotNull();
assertThat(file2.getId()).isNotNull();
- checkTables("insert", new String[] {"created_at"}, "projects");
+ checkTables("insert", "projects");
// SONAR-3636 : created_at must be fed when inserting a new entry in the 'projects' table
ResourceDto fileLoadedFromDB = dao.getResource(file1.getId());
assertThat(fileLoadedFromDB.getCreatedAt()).isNotNull();
+ assertThat(fileLoadedFromDB.getAuthorizationUpdatedAt()).isNotNull();
}
@Test
assertThat(dao.getLastSnapshotByResourceId(42L, session)).isNull();
}
+ @Test
+ public void update_authorization_date() {
+ setupData("update_authorization_date");
+
+ when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-03").getTime());
+ dao.updateAuthorizationDate(1L);
+
+ checkTables("update_authorization_date", "projects");
+ }
+
private List<String> getKeys(final List<Component> components) {
return newArrayList(Iterables.transform(components, new Function<Component, String>() {
@Override
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.utils.System2;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
@Before
public void setUp() {
- dao = new AuthorDao(getMyBatis(), new ResourceDao(getMyBatis()));
+ dao = new AuthorDao(getMyBatis(), new ResourceDao(getMyBatis(), System2.INSTANCE));
}
@Test
<user_roles id="1" user_id="200" resource_id="123" role="user"/>
<user_roles id="2" user_id="200" resource_id="123" role="admin"/>
-</dataset>
\ No newline at end of file
+ <projects id="100" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
<user_roles id="1" user_id="200" resource_id="123" role="user"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2010-01-01"/>
+
+</dataset>
<dataset>
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2010-01-01"/>
+
<groups id="100" name="sonar-administrators" />
<groups id="101" name="sonar-users" />
<group_roles id="1" group_id="100" resource_id="123" role="admin"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
<group_roles id="1" group_id="100" resource_id="123" role="admin"/>
<group_roles id="2" group_id="100" resource_id="123" role="user"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+</dataset>
<user_roles id="1" user_id="200" resource_id="123" role="user"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
<user_roles id="1" user_id="200" resource_id="123" role="user"/>
<user_roles id="2" user_id="200" resource_id="123" role="admin"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+</dataset>
<group_roles id="1" group_id="100" resource_id="123" role="admin"/>
<group_roles id="2" group_id="[null]" resource_id="123" role="user"/>
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+
</dataset>
<group_roles id="1" group_id="100" resource_id="123" role="admin"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+
+</dataset>
<group_roles id="1" group_id="100" resource_id="123" role="admin"/>
<group_roles id="2" group_id="100" resource_id="123" role="user"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-03"/>
+
+</dataset>
<group_roles id="1" group_id="100" resource_id="123" role="admin"/>
-</dataset>
\ No newline at end of file
+ <projects id="123" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="2014-09-01"/>
+
+</dataset>
<!-- root project -->
<projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
description="the description" long_name="Apache Struts"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="[null]"/>
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="[null]"
+ created_at="2008-12-02" authorization_updated_at="2014-09-03"/>
<snapshots id="1" project_id="1" parent_snapshot_id="[null]" root_project_id="1" root_snapshot_id="[null]"
status="P" islast="[true]" purge_status="[null]"
period1_mode="[null]" period1_param="[null]" period1_date="[null]"
<!-- module -->
<projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
scope="PRJ" qualifier="BRC" long_name="Struts Core"
- description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]"/>
+ description="[null]" enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]"
+ created_at="2008-12-02" authorization_updated_at="[null]"/>
<snapshots id="2" project_id="2" parent_snapshot_id="1" root_project_id="1" root_snapshot_id="1"
status="P" islast="[true]" purge_status="[null]"
period1_mode="[null]" period1_param="[null]" period1_date="[null]"
<projects long_name="org.struts" id="3" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
name="src/org/struts" root_id="2"
description="[null]"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" authorization_updated_at="[null]"/>
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts"
+ created_at="2008-12-02" authorization_updated_at="[null]"/>
<snapshots id="3" project_id="3" parent_snapshot_id="2" root_project_id="1" root_snapshot_id="1"
status="P" islast="[true]" purge_status="[null]"
period1_mode="[null]" period1_param="[null]" period1_date="[null]"
<projects long_name="org.struts.RequestContext" id="4" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java"
name="RequestContext.java" root_id="2"
description="[null]"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" authorization_updated_at="[null]"/>
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java"
+ created_at="2008-12-02" authorization_updated_at="[null]"/>
<snapshots id="4" project_id="4" parent_snapshot_id="3" root_project_id="1" root_snapshot_id="1"
status="P" islast="[true]" purge_status="[null]"
<projects id="1" root_id="[null]" scope="FIL" qualifier="FIL" kee="org.struts:struts:/src/main/java/org/struts/Action.java" name="Action"
description="[null]" long_name="org.struts.Action"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="[null]" path="/foo/bar" deprecated_kee="org.struts:struts:org.struts.Action"
- authorization_updated_at="[null]"/>
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="2014-09-03" path="/foo/bar" deprecated_kee="org.struts:struts:org.struts.Action"
+ authorization_updated_at="2014-09-03"/>
<projects id="2" root_id="[null]" scope="FIL" qualifier="FIL" kee="org.struts:struts:/src/main/java/org/struts/Filter.java" name="Filter"
description="[null]" long_name="org.struts.Filter"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="[null]" path="[null]" deprecated_kee="org.struts:struts:org.struts.Filter"
- authorization_updated_at="[null]"/>
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" created_at="2014-09-03" path="[null]" deprecated_kee="org.struts:struts:org.struts.Filter"
+ authorization_updated_at="2014-09-03"/>
</dataset>
--- /dev/null
+<dataset>
+
+ <projects id="1" root_id="200" scope="PRJ" qualifier="TRK" kee="old key" name="old name"
+ description="old name" long_name="old long name"
+ enabled="[false]" language="old" copy_resource_id="2" person_id="3" created_at="[null]" path="/old/foo/bar" deprecated_kee="old deprecated key"
+ authorization_updated_at="2014-09-03"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <projects id="1" root_id="200" scope="PRJ" qualifier="TRK" kee="old key" name="old name"
+ description="old name" long_name="old long name"
+ enabled="[false]" language="old" copy_resource_id="2" person_id="3" created_at="[null]" path="/old/foo/bar" deprecated_kee="old deprecated key"
+ authorization_updated_at="[null]"/>
+
+</dataset>